一、连接池
连接是可以复用的,但是我们每次数据库操作,其实我们都是把连接给close掉了,接下来我们要做的事就是把连接复用起来,复用连接不仅是提升性能,也提升程序的响应时间,接下来我们用连接池的技术把连接复用起来。
二、数据库连接池作用
总结缺点:
- 不使用数据库连接池,每次都通过
DriverManager
获取新连接,用完直接抛弃断开,连接的利用率太低,太浪费。 - 对于数据库服务器来说,压力太大了。我们数据库服务器和 Java 程序对连接数也无法控制,很容易导致数据库服务器崩溃。
我们就希望能管理连接。
- 我们可以建立一个连接池,这个池中可以容纳一定数量的连接对象。一开始,我们可以先帮用户创建好一些连接对象,用户要拿连接对象时,就直接从池中拿,而不是新建了。这样也可以节省时间。用完后,放回去,别人可以接着用。
- 可以提高连接的使用率。池中的用的有的连接用完了,那么连接池可以向服务器申请新的连接放到池中。
- 直到池中的连接达到“最大连接数”,就不能再申请新的连接了,如果没有拿到连接的用户只能等待。
三、市面常见连接池产品和对比
连接池是一套JAVA提供的标准,在这个标准下,谁都可以实现。
java.sql.DataSource接口
,这个接口里面规范了连接池获取连接的方法、规范了连接池回收连接的方法,不管是什么连接池,都得使用 DataSource = 第三方连接池的实现;
。
JDBC 的数据库连接使用 javax.sql.DataSource
接口进行规范,所有的第三方连接池都实现此接口,省了添加具体实现!也就是说,所有连接池获取连接的和回收连接方法都一样,不同的只有性能和扩展功能!
- DBCP 是 Apache 提供的数据库连接池,速度相对 c3p0 较快,但因自身存在 BUG
- C3P0 是一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性还可以
- Proxool 是 sourceforge 下的一个开源项目数据库连接池,有监控连接池状态的功能,稳定性较 c3p0 差一点
- Druid 是阿里提供的数据库连接池,据说是集 DBCP、C3P0、Proxool 优点于一身的数据库连接池,妥妥国货之光!!!
mock 性能数据(单位: ms)
5 | 20 | 50 | 100 | |
---|---|---|---|---|
tomcat-jdbc | 442 | 447 | 1,013 | 1,264 |
c3p0 | 4,480 | 5,527 | 7,449 | 10,725 |
dbcp | 676 | 689 | 867 | 1,292 |
hikari | 38 | 33 | 38 | 30 |
druid | 291 | 293 | 562 | 985 |
功能对比
功能 | dbcp | druid | c3p0 | tomcat-jdbc | HikariCP |
---|---|---|---|---|---|
是否支持 PSCache | 是 | 是 | 是 | 否 | 否 |
监控 | jmx | jmx/log/http | jmx,log | jmx | jmx |
扩展性 | 弱 | 好 | 弱 | 弱 | 弱 |
sql 监控及解析 | 无 | 支持 | 无 | 无 | 无 |
代码 | 简单 | 中等 | 复杂 | 简单 | 简单 |
更新时间 | 2015.8.6 | 2015.10.10 | 2015.12.09 | 2015.12.3 | |
特点 | 依赖于 common-pool | 阿里开源,功能全面 | 历史久远,代码逻辑复杂,且不易维护 | 优化力度大,功耗低 | boneCP |
连接池管理 | LinkedBlockingDeque | 数组 | FairBlockingQueue | threadlocal+ConcurrentBag |
通过性能与扩展性的对比,最终选择使用druid连接池。
四、国货之光 druid 连接池使用
druid连接池是第三方的,需要导入 druid 工具类 jar
可以发现,DruidDataSource也实现了DataSource接口,这就叫做连接池对象。
硬编码方式(了解,不推荐)
1. 创建一个druid连接池对象
2. 设置连接池参数 [必须 | 非必须]
3. 获取连接 [通用方法, 所有连接池都一样]
4. 回收连接 [通用方法, 所有连接池都一样]
package com.atguigu.api.druid;
import com.alibaba.druid.pool.DruidDataSource;
import org.junit.Test;
import java.sql.Connection;
import java.sql.SQLException;
public class DruidUsePart {
/**
* 创建druid连接池对象,使用硬编码进行核心参数设置!
* 必须参数: 连接数据库驱动类的全限定符,用于注册驱动
* 账号
* 密码
* url
* driverClass,这个是我们驱动的地址
* 非必须参数:
* 初始化数量
* 最大数量、等待时间等等 不推荐设置,因为你掌握不好它的一个度,不设置它也是有默认值的
*
*/
@Test
public void druidHard() throws SQLException {
// 注册驱动和创建连接的工作都交给了druid连接池做
DruidDataSource dataSource = new DruidDataSource();
// 设置四个必须参数,这四个参数设置好了后,它就能根据我们的信息帮我们完成驱动注册和获取文件
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setUrl("jdbc:mysql:///day01");
// 非必须
// 设置初始化连接数量
dataSource.setInitialSize(5);
// 设置最大连接数量
dataSource.setMaxActive(10);
// 设置等待时间
dataSource.setMaxWait(3000);
// 通过连接池获取连接
// DruidPooledConnection connection = dataSource.getConnection();
// PS:它返回的是包装的DruidPooledConnection,但DruidPooledConnection是实现了Connection接口的,所以这里我们可以直接使用Connection接收
Connection connection = dataSource.getConnection();
// JDBC的步骤
// 回收连接
connection.close(); // 如果是连接池调用close,那就是回收连接。因为我们刚刚看见了,我们拿到的这个connection其实不是原来的connection了,它其实是一个包装类,它里面做了优化,当你调用close方法后,是回收连接,即放回到连接池
}
}
硬编码是在Java代码中去设置这些参数,这一旦设置好后,程序运行起来后是无法修改的,这就叫硬编码。
软编码方式
外部配置 存放在 src/druid.properties
# key = value => java Properties??(key | value)
# druid连接池需要的配置参数,key必须固定命名
driverClassName=com.mysql.cj.jdbc.Driver
username=root
password=123456
url=jdbc:mysql://localhost:3306/itcast
druid 声明代码
/**
* 不直接在java代码编写配置文件,利用工厂模式,传入配置文件对象,创建连接池!
* @throws Exception
*/
@Test
public void druidSoft() throws Exception {
//1.读取外部配置文件 Properties
Properties properties = new Properties();
//src下的文件可以使用类加载器提供的方法,路径是相对于src来说的
InputStream ips = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(ips);
// 根据properties对象,去创建一个连接池对象
DataSource dataSource = DataSourceFactory.createDataSource(properties);
}
druid 配置(了解)
/**
* 通过读取外部配置文件的方法,实例化druid连接池对象
* 不直接在java代码编写配置文件,利用工厂模式,传入配置文件对象,创建连接池!
* @throws Exception
*/
@Test
public void druidSoft() throws Exception {
Properties properties = new Properties();
InputStream ips = DruidUsePart.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(ips);
// 根据properties对象,利用连接池的工具类的工厂模式,去创建一个连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
// 获取连接
Connection connection = dataSource.getConnection();
// 回收连接
connection.close();
}
这样做的好处是:我们可以通过修改外部配置文件,进而去影响连接池相关的属性。
五、druid源码
这里解释一下为什么这些key需要固定命名。
硬编码中,我们是直接new的druid连接池,new完后直接设置属性
DruidDataSource dataSource = new DruidDataSource();
软编码中,我们不是直接new,而是通过工厂,工厂底层其实也是new
往下滑,就可以看见我们刚刚设置的必须参数了