2022.4.29 数据库连接池
数据库连接池
数据库连接池简介
-
数据库连接池是个容器,负责分配、管理数据库连接(Connection)
-
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;
-
释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
-
好处
-
资源重用
-
提升系统响应速度
-
避免数据库连接遗漏
-
之前我们代码中使用连接是没有使用都创建一个Connection对象,使用完毕就会将其销毁。这样重复创建销毁的过程是特别耗费计算机的性能的及消耗时间的。
而数据库使用了数据库连接池后,就能达到Connection对象的复用,如下图
连接池是在一开始就创建好了一些连接(Connection)对象存储起来。用户需要连接数据库时,不需要自己创建连接,而只需要从连接池中获取一个连接进行使用,使用完毕后再将连接对象归还给连接池;这样就可以起到资源重用,也节省了频繁创建连接销毁连接所花费的时间,从而提升了系统响应的速度。
数据库连接池实现
-
标准接口:DataSource
官方(SUN) 提供的数据库连接池标准接口,由第三方组织实现此接口。该接口提供了获取连接的功能:
1 Connection getConnection()
那么以后就不需要通过
DriverManager
对象获取Connection
对象,而是通过连接池(DataSource)获取Connection
对象。 -
常见的数据库连接池
-
DBCP
-
C3P0
-
Druid
我们现在使用更多的是Druid,它的性能比其他两个会好一些。
-
-
Druid(德鲁伊)
-
Druid连接池是阿里巴巴开源的数据库连接池项目
-
功能强大,性能优秀,是Java语言最好的数据库连接池之一
-
Driud使用
-
导入jar包 druid-1.1.12.jar
-
定义配置文件
-
加载配置文件
-
获取数据库连接池对象
-
获取连接
项目结构如下:
编写配置文件如下:
1 driverClassName=com.mysql.jdbc.Driver 2 url=jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true 3 username=root 4 password=1234 5 # 初始化连接数量 6 initialSize=5 7 # 最大连接数 8 maxActive=10 9 # 最大等待时间 10 maxWait=3000
使用druid的代码如下:
1 /** 2 * Druid数据库连接池演示 3 */ 4 public class DruidDemo { 5 6 public static void main(String[] args) throws Exception { 7 //1.导入jar包 8 //2.定义配置文件 9 //3. 加载配置文件 10 Properties prop = new Properties(); 11 prop.load(new FileInputStream("jdbc-demo/src/druid.properties")); 12 //4. 获取连接池对象 13 DataSource dataSource = DruidDataSourceFactory.createDataSource(prop); 14 15 //5. 获取数据库连接 Connection 16 Connection connection = dataSource.getConnection(); 17 System.out.println(connection); //获取到了连接后就可以继续做其他操作了 18 19 } 20 }
druid配置详解
属性 | 说明 | 建议值 |
---|---|---|
url | 数据库的jdbc连接地址。一般为连接oracle/mysql。示例如下: | |
mysql : jdbc:mysql://ip:port/dbname?option1&option2&… | ||
oracle : jdbc:oracle:thin:@ip:port:oracle_sid | ||
username | 登录数据库的用户名 | |
password | 登录数据库的用户密码 | |
initialSize | 启动程序时,在连接池中初始化多少个连接 | 10-50已足够 |
maxActive | 连接池中最多支持多少个活动会话 | |
maxWait | 程序向连接池中请求连接时,超过maxWait的值后,认为本次请求失败,即连接池 | 100 |
没有可用连接,单位毫秒,设置-1时表示无限等待 | ||
minEvictableIdleTimeMillis | 池中某个连接的空闲时长达到 N 毫秒后, 连接池在下次检查空闲连接时,将回收该连接,要小于防火墙超时设置net.netfilter.nf_conntrack_tcp_timeout_established的设置 | 见说明部分 |
timeBetweenEvictionRunsMillis | 检查空闲连接的频率,单位毫秒, 非正整数时表示不进行检查 | |
keepAlive | 程序没有close连接且空闲时长超过 minEvictableIdleTimeMillis,则会执行validationQuery指定的SQL,以保证该程序连接不会池kill掉,其范围不超过minIdle指定的连接个数。 | true |
minIdle | 回收空闲连接时,将保证至少有minIdle个连接. | 与initialSize相同 |
removeAbandoned | 要求程序从池中get到连接后, N 秒后必须close,否则druid 会强制回收该连接,不管该连接中是活动还是空闲, 以防止进程不会进行close而霸占连接。 | false,当发现程序有未正常close连接时设置为true |
removeAbandonedTimeout | 设置druid 强制回收连接的时限,当程序从池中get到连接开始算起,超过此值后,druid将强制回收该连接,单位秒。 | 应大于业务运行最长时间 |
logAbandoned | 当druid强制回收连接后,是否将stack trace 记录到日志中 | true |
testWhileIdle | 当程序请求连接,池在分配连接时,是否先检查该连接是否有效。(高效) | true |
validationQuery | 检查池中的连接是否仍可用的 SQL 语句,drui会连接到数据库执行该SQL, 如果正常返回,则表示连接可用,否则表示连接不可用 | |
testOnBorrow | 程序 申请 连接时,进行连接有效性检查(低效,影响性能) | false |
testOnReturn | 程序 返还 连接时,进行连接有效性检查(低效,影响性能) | false |
poolPreparedStatements | 缓存通过以下两个方法发起的SQL: | true |
public PreparedStatement prepareStatement(String sql) | ||
public PreparedStatement prepareStatement(String sql, | ||
int resultSetType, int resultSetConcurrency) | ||
maxPoolPrepareStatementPerConnectionSize | 每个连接最多缓存多少个SQL | 20 |
filters | 这里配置的是插件,常用的插件有: | stat,wall,slf4j |
监控统计: filter:stat | ||
日志监控: filter:log4j 或者 slf4j | ||
防御SQL注入: filter:wall | ||
connectProperties | 连接属性。比如设置一些连接池统计方面的配置。 | |
druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 | ||
比如设置一些数据库连接属性: |
DBCP
需要用到的jar包
commons-pool-1.6 commons-dbcp-1.4
添加dbcp配置文件
配置文件中内容
1 #连接设置 这里的名字是dbcp数据源中定义好的 2 driverClassName=com.mysql.jdbc.Driver 3 url=jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=true 4 username=root 5 password=123456 6 7 #<!-- 初始化连接 --> 8 initialSize=10 9 10 #最大连接数量 11 maxActive=50 12 13 #<!-- 最大空闲连接 --> 14 maxIdle=20 15 16 #<!-- 最小空闲连接 --> 17 minIdle=5 18 19 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --> 20 maxWait=60000 21 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 22 #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。 23 connectionProperties=useUnicode=true;characterEncoding=UTF8 24 25 #指定由连接池所创建的连接的自动提交(auto-commit)状态。 26 defaultAutoCommit=true 27 28 #driver default 指定由连接池所创建的连接的只读(read-only)状态。 29 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix) 30 defaultReadOnly= 31 32 #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 33 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE 34 defaultTransactionIsolation=READ_UNCOMMITTED
使工具类读取配置文件:在自己创建的工具包中创建一个工具类
1 package com.xing.lesson05.utils; 2 3 import org.apache.commons.dbcp.BasicDataSourceFactory; 4 5 import javax.sql.DataSource; 6 import java.io.InputStream; 7 import java.sql.*; 8 import java.util.Properties; 9 10 public class JdbcUtils_DBCP { 11 private static DataSource dataSource = null; 12 static { 13 try {// 返回输入流 类加载器 拿到资源 需要加载的文件名 14 InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"); 15 Properties properties = new Properties(); 16 properties.load(in);//抛出一个catch 17 18 //创建数据源 工厂模式:创建对象 19 dataSource = BasicDataSourceFactory.createDataSource(properties); 20 } catch (Exception e) { 21 e.printStackTrace(); 22 } 23 } 24 //获取连接 25 public static Connection getConnection() throws SQLException { 26 return dataSource.getConnection();//从数据源获取链接 27 } 28 29 //释放连接 顺序不能错 30 public static void release(Connection conn, Statement st, ResultSet rs){ 31 if (rs != null) { 32 try { 33 rs.close(); 34 } catch (SQLException e) { 35 e.printStackTrace(); 36 } 37 } 38 if (st != null) { 39 try { 40 st.close(); 41 } catch (SQLException e) { 42 e.printStackTrace(); 43 } 44 } 45 if (conn != null) { 46 try { 47 conn.close(); 48 } catch (SQLException e) { 49 e.printStackTrace(); 50 } 51 } 52 } 53 }
插入测试
1 package com.xing.lesson05; 2 3 import com.xing.lesson05.utils.JdbcUtils_DBCP; 4 5 import java.sql.Connection; 6 import java.sql.PreparedStatement; 7 import java.sql.SQLException; 8 import java.util.Date; 9 10 public class TestDBCP { 11 public static void main(String[] args) { 12 Connection conn = null; 13 PreparedStatement st = null; 14 try { 15 conn = JdbcUtils_DBCP.getConnection(); 16 //区别 使用?占位符代替参数 17 String sql = "insert into users(id,`NAME`,`PASSWORD`,`email`,`birthday`) VALUE(?,?,?,?,?)"; 18 19 st = conn.prepareStatement(sql);//预编译 先写sql 然后不执行 20 21 //手动给参数赋值 22 st.setInt(1,4);//给第1个参数?(对应id)赋值为4 不知道类型用setObject(); 23 st.setString(2,"xiaohong"); 24 st.setString(3,"132213"); 25 st.setString(4,"4654656@qq.com"); 26 27 // util.Data Java new Date().getTime()获得时间戳 28 // sql.Data 数据库 new java.sql.Date转化为sql时间 29 st.setDate(5,new java.sql.Date(new Date().getTime())); 30 31 //执行 区别 不用传参 32 int i = st.executeUpdate(); 33 if(i>0){ 34 System.out.println("插入成功"); 35 } 36 37 } catch (SQLException e) { 38 e.printStackTrace(); 39 }finally { 40 JdbcUtils_DBCP.release(conn,st,null); 41 } 42 } 43 }
C3P0
需要用到的jar包。c3p0-0.9.5.5jar mchange-commons-java-0.2.19jar
添加c3p0配置文件 xml格式
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!--可以配置多套数据源--> 3 <c3p0-config> 4 <!-- 5 c3p0的缺省(默认)配置 6 如果在代码中"ComboPooledDataSource ds=new ComboPooledDataSource();"这样写就表示使用的是c3p0的缺省(默认) 7 --> 8 <default-config> 9 <property name="driverClass">com.mysql.jdbc.Driver</property> 10 <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=true</property> 11 <property name="user">root</property> 12 <property name="password">root</property> 13 <property name="acquiredIncrement">5</property> 14 <property name="initialPoolSize">10</property> 15 <property name="minPoolSize">5</property> 16 <property name="maxPoolSize">20</property> 17 </default-config> 18 <!-- 19 C3P0的命名配置. 20 如果在代码中ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");这样写就表示使用的是name是MySQL的配置信息来创建数据源 21 --> 22 <named-config name="MySQL"> 23 <property name="driverClass">com.mysql.jdbc.Driver</property> 24 <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=true</property> 25 <property name="user">root</property> 26 <property name="password">123456</property> 27 <property name="acquiredIncrement">5</property> 28 <property name="initialPoolSize">10</property> 29 <property name="minPoolSize">5</property> 30 <property name="maxPoolSize">20</property> 31 </named-config> 32 </c3p0-config>
使工具类读取配置文件:在自己创建的工具包中创建一个工具类
1 package com.xing.lesson05.utils; 2 3 import com.mchange.v2.c3p0.ComboPooledDataSource; 4 import org.apache.commons.dbcp.BasicDataSourceFactory; 5 6 import javax.sql.DataSource; 7 import java.io.InputStream; 8 import java.sql.Connection; 9 import java.sql.ResultSet; 10 import java.sql.SQLException; 11 import java.sql.Statement; 12 import java.util.Properties; 13 14 public class JdbcUtils_C3P0 { 15 private static DataSource dataSource = null; 16 static { 17 try { 18 //ComboPooledDataSource();不写参数使用默认的数据源 写参数使用自己创建的数据源 19 dataSource = new ComboPooledDataSource("MySQL");//配置文件写法 20 } catch (Exception e) { 21 e.printStackTrace(); 22 } 23 } 24 //获取连接 25 public static Connection getConnection() throws SQLException { 26 return dataSource.getConnection();//从数据源获取链接 27 } 28 29 //释放连接 顺序不能错 30 public static void release(Connection conn, Statement st, ResultSet rs){ 31 if (rs != null) { 32 try { 33 rs.close(); 34 } catch (SQLException e) { 35 e.printStackTrace(); 36 } 37 } 38 if (st != null) { 39 try { 40 st.close(); 41 } catch (SQLException e) { 42 e.printStackTrace(); 43 } 44 } 45 if (conn != null) { 46 try { 47 conn.close(); 48 } catch (SQLException e) { 49 e.printStackTrace(); 50 } 51 } 52 } 53 }
插入测试
1 package com.xing.lesson05.utils; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.SQLException; 6 import java.util.Date; 7 8 public class TestC3P0 { 9 public static void main(String[] args) { 10 Connection conn = null; 11 PreparedStatement st = null; 12 try { 13 conn = JdbcUtils_C3P0.getConnection(); 14 15 //区别 使用?占位符代替参数 16 String sql = "insert into users(id,`NAME`,`PASSWORD`,`email`,`birthday`) VALUE(?,?,?,?,?)"; 17 18 st = conn.prepareStatement(sql);//预编译 先写sql 然后不执行 19 20 //手动给参数赋值 21 st.setInt(1,5); 22 st.setString(2,"xiaohong"); 23 st.setString(3,"132213"); 24 st.setString(4,"4654656@qq.com"); 25 26 // util.Data Java new Date().getTime()获得时间戳 27 // sql.Data 数据库 new java.sql.Date转化为sql时间 28 st.setDate(5,new java.sql.Date(new Date().getTime())); 29 30 //执行 区别 不用传参 31 int i = st.executeUpdate(); 32 if(i>0){ 33 System.out.println("插入成功"); 34 } 35 36 } catch (SQLException e) { 37 e.printStackTrace(); 38 }finally { 39 JdbcUtils_C3P0.release(conn,st,null); 40 } 41 } 42 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?