文章目录
- 1.Druid的简单介绍
- 2.使用举例
- 2.1 正常不使用数据库连接池操作数据库
- 2.1使用数据库连接池
1.Druid的简单介绍
Druid(德鲁伊)是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。 官网:https://github.com/alibaba/druid(访问比较慢,所以你懂的)要使用Druid连接池,首先把jar包导入项目,通过
druid.properties配置文件进行配置。(配置文件名称自定义不是非得叫druid的)
- 普通的项目,没有使用maven进行管理的,需要自己去导入jar包;
- maven项目工程,直接在pom.xml中进行配置
Java 中的 properties 文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文本文件。
- 文件的内容是格式是 “键=值”(key-value) 的格式。
- 在 properties 文件中,可以用"#" 来作注释。
properties文件在Java编程中用到的地方很多,操作很方便。
介于此,我们可以把数据库连接信息,如驱动、URL、账号、密码等这些动态信息不必写在class中,而放入一个可读取的配置的属性文件中,程序从属性文件中读取值以实现"运行时动态加载"。常用的参数如下:
https://github.com/alibaba/druid/wiki/DruidDataSource配置属性列表DruidDataSource支持哪些数据库:
(理论上说,支持所有有jdbc驱动的数据库。实际测试过的有)
2.使用举例
当然,在连接数据库时,我们也是要导入对应的驱动jar包的,
这里默认大家都已经导入,咱们只是探讨连接库时的写法
http://ftp.jaist.ac.jp/pub/mysql/Downloads/Connector-J/
例如:
2.1 正常不使用数据库连接池操作数据库
在不使用这些第三方的工具jar包时,我们连接数据库,可能是这样子的(以mysql为例啊)
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//要连接的数据库的url(地址),不同的数据库,写法不一样
String url = "jdbc:mysql://localhost:3306/jdbc_db";
//你登录的用户名
String user = "用户名";
//你登录的密码
String password = "密码";
//获取一个连接 conn
Connection conn =DriverManager.getConnection(url, user, password);
完整举例:
import java.sql.*;
/**
* @author hyl
* @version 1.0
* @date 2022/12/3-15:39
*/
public class java02 {
public static void main(String[] args) {
Connection conn=null;
ResultSet resultSet=null;
Statement statement=null;
try {
//注册驱动
//说明一下,这里我的是8版本所以要加上cj,5版本的不加
Class.forName("com.mysql.cj.jdbc.Driver");
//要连接的数据库的url(地址),不同的数据库,写法不一样
String url = "jdbc:mysql://localhost:3307/sms";
//你登录的用户名
String user = "root";
//你登录的密码
String password = "123456";
//获取一个连接 conn
conn= DriverManager.getConnection(url, user, password);
} catch (Exception e) {
e.printStackTrace();
}
try {
statement= conn.createStatement();
resultSet= statement.executeQuery("select * from user");
while (resultSet.next()){
//可以通过索引,也可以通过对应的名称
System.out.println("方式一通过索引:"+resultSet.getString(1)+" "+resultSet.getString(2)
+" "+resultSet.getString(3));
/*System.out.println("方式二通过名称"+resultSet.getString("Sno")+" "+resultSet.getString("username")
+" "+resultSet.getString("password"));*/
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
// 释放资源
try {
if (conn!=null){
conn.close();
}
if(statement!=null){
statement.close();
}
if(resultSet!=null){
resultSet.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
查询一下user表,并打印输出里面的内容:
我们可以看到,传统的写法是很麻烦的,每次需要操作数据库,都要写一大堆的连接“配置”,而且每次连接的获取与释放都是要耗费电脑资源的,很不方便。
2.1使用数据库连接池
好处:
- 资源重用
由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。- 更快的系统响应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。- 新的资源分配手段
对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术,几年钱也许还是个新鲜话题,对于目前的业务系统而言,如果设计中还没有考虑到连接池的应用。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。- 统一的连接管理,避免数据库连接泄漏
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。
在说连接池的使用前,我们先说下Properties类与Properties配置文件
- Properties类与Properties配置文件
Properties类继承自Hashtable类并且实现了Map接口,也是使用一种键值对的形式来保存属性集。不过Properties有特殊的地方,就是它的键和值都是字符串类型。- Properties中的主要方法
(1)load(InputStream inStream)
这个方法可以从.properties属性文件对应的文件输入流中,加载属性列表到Properties类对象。如下面的代码:
(2)store(OutputStream out, String comments)
这个方法将Properties类对象的属性列表保存到输出流中。如下面的代码:
如果comments不为空,保存后的属性文件第一行会是#comments,表示注释信息;如果为空则没有注释信息。注释信息后面是属性文件的当前保存时间信息。
(3)getProperty/setProperty
这两个方法是分别是获取和设置属性信息。
使用配置文件的时候,只是把这些内容放到了druid.properties文件中(名字自定义,习惯使用druid)。
druid.properties(放到资源目录下)
#==============正常配置=============
#key=value 注释说明是以该种形式写入文件的
# 指明驱动(数据库的类别,可写可不写,不写会根据url自动匹配)
driverClassName=com.mysql.cj.jdbc.Driver
# 指明要操作的数据库url
# localhost指的是本地ip(127.0.0.1)也就是要访问的是本地的数据库
#3006是对应的端口号,mysql默认是3306,根据需求,端口号可能会改变
# sms就是你要操作的数据库中的具体的那个库,当然也可以具体到表
#?rewriteBatchedStatements=true 可要可不要,作用是是否允许批处理
#如果操作的是本地数据库,且端口号不变,可以简写为:url=jdbc:mysql:///sms
url=jdbc:mysql://localhost:3306/sms?rewriteBatchedStatements=true
# 登录数据库的用户名
username=root
# 登录数据库的密码
password=123456
#=========下面是数据库连接池的配置=====
#initial connection Size 初始化连接数10个
initialSize=10
#min idle connecton size 最小连接数5个
minIdle=5
#max active connection size 最大连接数50个
maxActive=50
#max wait .time (5000 mil seconds)
#最大等待时间5s,就是有新的请求索要连接时,如果池子里面没有可用连接了,
#我最多等待5s,5s的时间还没拿到,就放弃本次的索求
maxWait=5000
采用类加载器ClassLoader得到指定文件名properties文件的的输入流,进而用DruidDataSourceFactory的createDataSource方法获取连接池对象
浅看一下DruidDataSourceFactory.createDataSource()的源码:他会自动的去读取我们写的配置文件,并进行对应的设置,因此在写配置文件时,像url,driverClassName这些key的时候一定要与之对应,不能乱写
JDBCUtil.java
package com.hyl.sams.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileReader;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* 德鲁伊连接池工具类
* 连接池工具类,连接数据库
* @author hyl
*/
public class JDBCUtil {
private static DataSource source;
//初始化连接
static {
Properties properties = new Properties();
try {
//使用ClassLoader加载配置文件,获取字节输入流
InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(is);
source = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return source.getConnection();
}
/**
* 释放连接(不是断掉连接,而是归还释放)
* @param resultSet
* @param statement
* @param connection
*/
public static void Close(ResultSet resultSet, Statement statement, Connection connection){
try {
if (resultSet!=null) {
resultSet.close();
}
if (statement!=null) {
statement.close();
}
if (connection!=null) {
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
上述代码,只需通过JDBCUtil.getConnection()就可以从池子里面获取一个连接,也只是方便我们去获取数据库的连接,但是当我们要去操作数据库的时候,还不是很方便,这里我们去借助第三方的数据库工具jar包,去简化我们的sql操作。
BasicDao.java
package com.hyl.sams.dao;
import com.hyl.sams.utils.Jdbc_Druid_Utils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* @author hyl
*/
public class BasicDao {
private QueryRunner qr=new QueryRunner();
//统一说明:Object... parameters
// 是动态传参,参数个数0-n
/**
* 插入、更新或删除
* @param sql
* @param parameters
* @return
*/
public int update(String sql,Object... parameters){
Connection connection=null;
try {
connection= JDBCUtil.getConnection();
int update = qr.update(connection, sql, parameters);
return update;
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JDBCUtil.Close(null,null,connection);
}
}
/**
* 返回多行记录
* @param sql
* @param tClass
* @param parameters
* @param <T>
* @return
*/
public <T> List<T> queryMulti(String sql, Class<T> tClass, Object... parameters){
Connection connection=null;
try {
connection= JDBCUtil.getConnection();
return qr.query(connection, sql, new BeanListHandler<T>(tClass), parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JDBCUtil.Close(null,null,connection);
}
}
/**
* 返回单行
* @param sql
* @param tClass
* @param parameters
* @param <T>
* @return
*/
public <T> T querySingle(String sql, Class<T> tClass, Object... parameters){
Connection connection=null;
try {
connection= JDBCUtil.getConnection();
return qr.query(connection, sql, new BeanHandler<T>(tClass), parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JDBCUtil.Close(null,null,connection);
}
}
/**
* 返回单行单列
* @param sql
* @param parameters
* @return
*/
public Object queryScalar(String sql,Object...parameters){
Connection connection=null;
try {
connection= JDBCUtil.getConnection();
return qr.query(connection, sql, new ScalarHandler<>(),parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JDBCUtil.Close(null,null,connection);
}
}
}
当我们做好上述的准备工作后,再要去写代码查询user表里面的数据:
我们需要先写好一个javaBean用于数据传输
User.java
public class User {
private String Sno;
private String username;
private String password;
public String getSno() {
return Sno;
}
public void setSno(String sno) {
Sno = sno;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
java01.java
import java.util.List;
/**
* @author hyl
* @version 1.0
* @date 2022/12/2-21:14
*/
public class Java01 {
private static BasicDao dao=new BasicDao();
public static void main(String [] args){
List<User> users = dao.queryMulti("select * from user", User.class);
for (User user : users) {
System.out.println(user.getSno()+" "+user.getUsername()+" "+user.getPassword());
}
}
}
上面标红是因为一些时区的配置,不影响正常使用(强迫症就自己搜一下,加上对应的设置吧,这里不是重点)
通过上面和下面的对比,就可以明显的发现我们使用数据库连接池和工具包的好处。