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&amp;characterEncoding=utf8&amp;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&amp;characterEncoding=utf8&amp;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  }
复制代码
 

无论使用什么数据源,本质还是一样的,DataSource接口不会变,方法就不会变

posted @   暴躁C语言  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示