数据库连接的建立、关闭资源消耗巨大。 传统数据库访问方式:一次数据访问对应一个物理连接,每次操作数据库都要打开关闭该物理连接,系统性能严重受损。 解决方案:数据库连接池。系统初始运行时,主动建立足够足够的连接,组成一个池,每次应用程序请求数据库连接时,无需重新打开连接,而是从池中取出已有的连接,使用完后,不再关闭,而是归还。

1.什么是数据库连接池
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
数据库连接池负责:连接建立、连接释放、连接管理、连接分配。
2.常见的数据库连接池产品
| 名称 | 简介 |
|---|---|
| C3P0 | 一个开放源代码的JDBC连接池,它在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。 |
| DBCP | Database Connection Pool)是一个依赖Jakarta commons-pool对象池机制的数据库连接池,Tomcat的数据源使用的就是DBCP。目前 DBCP 有两个版本分别是 1.3 和 1.4。 |
| Druid | 阿里开源的druid不单纯是一个连接池,还添加了监控功能,目前已经是国内最受欢迎的连接池组件。 |
| Hikari | Hikari连接池目前公认是性能最高的数据库连接池,同时也是SpringBoot2.0以后默认使用的数据库连接池。 |
3.JDBC使用Druid数据库连接池
1)下载druid.jar.
从以下网盘地址下载druid jar包。 druid网盘地址 密码:nquq
2)把mysql-connector-java-5.1.6-bin.jar和druid-1.0.9.jar复制到项目的lib目录下,全选作为项目类库。

3)在src 根目录下创建druid.properties属性文档。
#druid.properties文件的配置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/myschool?useUnicode=true&characterEncoding=UTF-8
username=root
password=root
#初始化连接数量
initialSize=5
#最大连接数
maxActive=20
#最新空闲数量
minIdle=5
#最大超时时间
maxWait=3000
4)在util包下创建DBUtils数据库工具类。
public class DBUtils {
//声明druid连接池对象
private static DruidDataSource dataSource =null;
private static Connection conn = null;
private static String url =null;
private static String username = null;
private static String password = null;
/**初始连接数**/
private static int initialSize;
/**最大活动连接数**/
private static int maxActive;
/**最小闲置连接数**/
private static int minIdle;
/**连接耗尽时最大等待获取连接时间**/
private static long maxWait;
private DBUtils(){
}
private static void initPool(){
try
{
Properties pro = new Properties();
InputStream in = DBUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(in); //读取属性文档配置信息
String driverClassName = pro.getProperty("driverClassName");
Class.forName(driverClassName);
url = pro.getProperty("url");
username = pro.getProperty("username");
password = pro.getProperty("password");
initialSize = Integer.parseInt(pro.getProperty("initialSize"));
maxActive = Integer.parseInt(pro.getProperty("maxActive"));
maxWait = Integer.parseInt(pro.getProperty("maxWait"));
minIdle = Integer.parseInt(pro.getProperty("minIdle"));
//创建druid数据源
dataSource = new DruidDataSource();
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
//设置连接池中初始连接数
dataSource.setInitialSize(initialSize);
//设置最大连接数
dataSource.setMaxActive(maxActive);
//设置最小的闲置链接数
dataSource.setMinIdle(minIdle);
//设置最大的等待时间(等待获取链接的时间)
dataSource.setMaxWait(maxWait);
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
//由于使用了数据库连接池,我们不采用单例模式
public static Connection getConnection ()throws Exception
{
if(dataSource==null){
initPool();
}
return dataSource.getConnection();
}
}
5)在test下编写测试类,测试。
public class DruidDBUtilsDemo {
public static void main(String[] args) {
try(Connection conn = DBUtils.getConnection()){
if(conn!=null){
System.out.println("MySQL连接成功!");
}
}catch(Exception ex){
ex.printStackTrace();
}
}
}
运行结果:
信息: {dataSource-1} inited
MySQL连接成功
4.JDBC使用Hikari数据库连接池
1).下载hikari的jar包。
链接:https://pan.baidu.com/s/1PnziTEET0oJrLlYDzIR5vw 提取码:9527
2).把HikariCP-3.1.0.jar和slf4j-api-1.7.25.jar复制到项目的lib目录下,全选作为项目类库。
3).在src下创建jdbc.properties
#MYSQL
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/myschool?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false&allowPublicKeyRetrieval=true
username=root
password=root
4).在util包下创建HikariJdbcUtil数据库工具类。
package util;
import com.zaxxer.hikari.HikariDataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
public class HikariJdbcUtil {
//声明hikari连接池对象
private static HikariDataSource dataSource = null;
private static Connection conn = null;
private static String url = null;
private static String username = null;
private static String password = null;
/**
* 初始连接数
**/
private static int initialSize;
/**
* 最大活动连接数
**/
private static int maxActive;
/**
* 最小闲置连接数
**/
private static int minIdle;
/**
* 连接耗尽时最大等待获取连接时间
**/
private static long maxWait;
private HikariJdbcUtil() {
}
private static void initPool() {
try {
Properties pro = new Properties();
InputStream in = HikariJdbcUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
pro.load(in); //读取属性文档配置信息
String driverClassName = pro.getProperty("driverClassName");
Class.forName(driverClassName);
url = pro.getProperty("url");
username = pro.getProperty("username");
password = pro.getProperty("password");
//创建druid数据源
dataSource = new HikariDataSource();
dataSource.setJdbcUrl(url);
//dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
} catch (Exception ex) {
ex.printStackTrace();
}
}
//由于使用了数据库连接池,我们不采用单例模式
public static Connection getConnection() throws Exception {
if (dataSource == null) {
initPool();
}
return dataSource.getConnection();
}
}
5).编写测试类,测试创建1万个连接再释放1万个连接的总耗时。
package com.test;
import util.HikariJdbcUtil;
import java.sql.Connection;
public class HikariPoolDemo {
public static void main(String[] args) throws Exception {
Connection conn = null;
long startTime = System.currentTimeMillis();
//统计一下总用时
for (int i = 0; i < 10000; i++) {
conn = HikariJdbcUtil.getConnection();
if (conn != null) {
conn.close();
conn = null;
}
}
long endTime = System.currentTimeMillis();
System.out.println("创建1万个连接,销毁1万个连接,总耗时:" + (endTime - startTime) + " ms");
}
}
运行结果:
创建1万个连接,销毁1万个连接,总耗时:958 ms
5.使用数据库连接池与不使用连接池的性能对比
不使用数据库连接池,一次创建100个连接对象。
public class NormalDBUtilsDemo {
private static final String url = "jdbc:mysql://localhost:3306/myschool?useUnicode=true&characterEncoding=UTF-8";
private static final String username = "root";
private static final String password = "root";
public static void main(String[] args) {
Connection conn = null;
long startTime = System.currentTimeMillis();
long endTime = -1;
try {
for(int i=0;i<100;i++) {
conn = DriverManager.getConnection(url, username, password);
conn.close();
conn=null;
}
endTime = System.currentTimeMillis();
System.out.println("总用时:" + (endTime - startTime)+"ms");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
运行结果:
总用时:1013ms
使用连接池,一次创建100个连接对象。
public class DruidDBUtilsDemo {
public static void main(String[] args) {
Connection conn = null;
long startTime = System.currentTimeMillis();
long endTime = -1;
try {
for (int i = 0; i < 100; i++) {
conn = DBUtils.getConnection();
conn.close();
conn=null;
}
endTime = System.currentTimeMillis();
System.out.println("总用时:" + (endTime - startTime) + "ms");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
运行结果:
信息: {dataSource-1} inited
总用时:409ms
说明使用了数据库连接池后,程序性能的提升还是很明显的。经过测试对比,我们发现Hikari和Druid以及手工创建连接,三者的性能对比如下:
hikari > druid > 手工创建连接