Java初学笔记42
十、数据库连接池
1. 如果一次性连接过多,数据库会怎么样?
@Test
public void test01(){
for (int i = 0; i < 5000; i++) {
//1. 获取连接
Connection connection = JDBCUtils.getConnection();
//2. 执行sql
// ...
}
}
如图,会抛出java.lang.RuntimeException: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"
连接过多的异常
2. 如果在某一刻访问数据库过多,时间开销如何?
时间开销会很大,就像某一时刻,一万人同时涌进肯德基买汉堡,店员肯定会崩溃
3. 以上传统连接存在的问题
(1)传统的JDBC数据库连接使用 DriverManager 来获取,每次向数据库建立连接的时候都要将Connection 加载到内存中,再验证IP地址,用户名和密码(0.05s ~1s时间)。需要数据库连接的时候,就向数据库要求一个,频繁的进行数据库连接操作将占用很多的系统资源,容易造成服务器崩溃。
(2)每一次数据库连接,使用完后都得断开,如果程序出现异常而未能关闭,将导致数据库内存泄漏,最终将导致重启数据库。
(3)传统获取连接的方式,不能控制创建的连接数量,如连接过多,也可能导致
内存泄漏,MySQL崩溃。
(4)解决传统开发中的数据库连接问题,可以采用数据库连接池技术 (connection pool)
4. 数据库连接池的基本介绍
(1)预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
(2)数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
(3)当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中
(4)数据库连接池示意
数据库连接池中,重复使用的“连接”,可以理解为:我给张三打电话说事情,说完后,我让张三接着把手机递给李四,我再和他通话。在这个过程中电话始终连接,比起我一个个打通电话省事很多。
5. 数据库连接池种类
(1)JDBC的数据库连接池使用javax.sqI.DataSource 来表示,DataSource
只是一个接口,该接口通常由第三方提供实现[提供.jar]
(2)▲C3PO数据库连接池,速度相对较慢,稳定性不错(hibernate, spring)
(3)DBCP数据库连接池,速度相对c3p0较快,但不稳定
(4)Proxool数据库连接池,有监控连接池状态的功能,稳定性较c3pO差一点
(5)BoneCP数据库连接池,速度快
(6)▲Druid(德鲁伊) 是阿里提供的数据库连接池,集DBCP、C3PO、Proxool优点于一身的数据库连接池
十一、C3P0使用举例
1. 手动指定相关配置(不推荐)
// 手动配置
@Test
public void test01() throws Exception {
//1. 创建一个数据源对象,即连接池
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
//2. 通过配置文件 mysql.properties 获取连接Mysql数据库的相关信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
//读取相关的属性值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
//3. 给连接池 comboPooledDataSource 设置相关的参数
comboPooledDataSource.setDriverClass(driver);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setJdbcUrl(url);
comboPooledDataSource.setPassword(password);
//设置初始化连接数 50个“连接”
comboPooledDataSource.setInitialPoolSize(50);
//设置最大连接数 100个“连接”
comboPooledDataSource.setMaxPoolSize(100);
//4. 测试5000个连接用时
long start = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
Connection connection = comboPooledDataSource.getConnection();
connection.close();
}
long end = System.currentTimeMillis();
System.out.println("使用C3P0连接池,耗时"+(end - start));
}
2. 使用C3P0配置好的文件(推荐)
//使用C3P0的模板
@Test
public void test02() throws Exception {
//1. 创建数据源,即连接池,输入模板自定义参数
/*
<!-- C3P0连接池的名字,可以自定义 -->
<named-config name="dazhi">
*/
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("dazhi");
//测试5000次连接耗时
long s = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
Connection connection = comboPooledDataSource.getConnection();
connection.close();
}
long e = System.currentTimeMillis();
System.out.println("耗时:"+(e - s));
}
c3p0.config.xml
(1)c3p0.config.xml 拷贝到 src 目录下
(2)修改模板参数
<c3p0-config>
<!-- C3P0连接池的名字,可以自定义 -->
<named-config name="dazhi">
<!-- 驱动类 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!-- url-->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/自己的数据库名</property>
<!-- 用户名 -->
<property name="user">数据库用户名</property>
<!-- 密码 -->
<property name="password">数据库密码</property>
<!-- 每次增长的连接数-->
<property name="acquireIncrement">5</property>
<!-- 初始的连接数 -->
<property name="initialPoolSize">10</property>
<!-- 最小连接数 -->
<property name="minPoolSize">5</property>
<!-- 最大连接数 -->
<property name="maxPoolSize">10</property>
<!-- 可连接的最多的命令对象数 -->
<property name="maxStatements">5</property>
<!-- 每个连接对象可连接的最多的命令对象数 -->
<property name="maxStatementsPerConnection">2</property>
</named-config>
</c3p0-config>