数据库连接池C3P0,DBCP教程详解示例

Posted java学习

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库连接池C3P0,DBCP教程详解示例相关的知识,希望对你有一定的参考价值。


Java学习
针对Java初学者以及自学者!
数据库连接池C3P0,DBCP教程详解示例
公告通知

如果你是初学者,或者是自学者!你可以加小编微信(xxf960513)!小编可以给你学习上,工作上的一些建议以及可以给你(免费)提供学习资料!最重要我们还可以交个朋友!你在学习上有什么问题都可以加小编微信进行私聊!小编都会为你解答!


  连接池

实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术,来共享连接Connection。这样我们就不需要每次都创建连接、释放连接了,这些操作都交给了连接池

1.1    连接池概述

l  概念

用池来管理Connection,这样可以重复使用Connection。有了池,所以我们就不用自己来创建Connection,而是通过池来获取Connection对象。当使用完Connection后,调用Connectionclose()方法也不会真的关闭Connection,而是把Connection“归还”给池。池就可以再利用这个Connection对象了。

数据库连接池C3P0,DBCP教程详解示例

l  规范

Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!

常见的连接池:DBCPC3P0

接下来,我们就详细的学习连接池。

1.2    C3P0连接池

C3P0开源免费的连接池!目前使用它的开源项目有:SpringHibernate等。使用第三方工具需要导入jar包,c3p0使用时还需要添加配置文件c3p0-config.xml

1.2.1    导入jar

我们使用的0.9.2版本,需要导入2jar

数据库连接池C3P0,DBCP教程详解示例 

1.2.2    核心类

@Test
public void demo01() throws Exception{
   //1 获得连接池(数据源)
   ComboPooledDataSource dataSource = new ComboPooledDataSource();
   //1.1 设置基本项
   dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/webdb_4");
   dataSource.setUser("root");
   dataSource.setPassword("root");
   //1.2其他项
   // * 初始化连接池中连接的个数
   dataSource.setInitialPoolSize(5);
   // * 最小|最大连接池中连接的个数
   dataSource.setMinPoolSize(2);
   dataSource.setMaxPoolSize(10);
   // * 最大空闲数
   dataSource.setMaxIdleTime(60);
   // * 每次增长个数
   dataSource.setAcquireIncrement(2);
   //2获得连接
   Connectionconn = dataSource.getConnection();
   System.out.println(conn);
}

1.2.3    配置文件

  • 配置文件名称:c3p0-config.xml (固定)

  • 配置文件位置:src (类路径)

  • 配置文件内容:命名配置

<c3p0-config>
   <!-- 命名的配置 -->
   <named-configname="itheima">
       <!--连接数据库的4项基本参数 -->
<propertyname="driverClass">com.mysql.jdbc.Driver</property>
  <propertyname="jdbcUrl">jdbc:mysql://127.0.0.1:3306/webdb</property>
       <propertyname="user">root</property>
       <propertyname="password">root</property>
       <!--如果池中数据连接不够时一次增长多少个-->
       <propertyname="acquireIncrement">5</property>
       <!--初始化连接数 -->
       <propertyname="initialPoolSize">20</property>
       <!--最小连接受 -->
       <propertyname="minPoolSize">10</property>
       <!--最大连接数 -->
       <propertyname="maxPoolSize">40</property>
       <!---JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量 -->
       <propertyname="maxStatements">0</property>
       <!--连接池内单个连接所拥有的最大缓存statements数 -->
<propertyname="maxStatementsPerConnection">5</property>
   </named-config>
</c3p0-config>
  • 配置文件内容:默认配置

<c3p0-config>
   <!-- 默认配置,如果没有指定则使用这个配置 -->
   <default-config>
     <propertyname="driverClass">com.mysql.jdbc.Driver</property>
     <propertyname="jdbcUrl">jdbc:mysql://127.0.0.1:3306/webdb</property>
       <propertyname="user">root</property>
       <propertyname="password">root</property>
       <propertyname="checkoutTimeout">30000</property>
      <propertyname="idleConnectionTestPeriod">30</property>
       <propertyname="initialPoolSize">10</property>
       <propertyname="maxIdleTime">30</property>
       <propertyname="maxPoolSize">100</property>
       <propertyname="minPoolSize">10</property>
       <propertyname="maxStatements">200</property>
       <user-overridesuser="test-user">
           <propertyname="maxPoolSize">10</property>
           <propertyname="minPoolSize">1</property>
           <propertyname="maxStatements">0</property>
       </user-overrides>
</default-config>

1.2.4    常见配置项

分类

属性

描述

必须项

user

用户名

password

密码

driverClass

驱动

mysql驱动,com.mysql.jdbc.Driver

jdbcUrl

路径

mysql路径,jdbc:mysql://localhost:3306/数据库

基本配置

acquireIncrement

连接池无空闲连接可用时,一次性创建的新连接数

默认值:3

initialPoolSize

连接池初始化时创建的连接数

默认值:3

maxPoolSize

连接池中拥有的最大连接数

默认值:15

minPoolSize

连接池保持的最小连接数。

maxIdleTime

连接的最大空闲时间。如果超过这个时间,某个数据库连接还没有被使用,则会断开掉这个连接,如果为0,则永远不会断开连接。

默认值:0

管理连接池的大小和连接的生存时间(扩展)

maxConnectionAge

配置连接的生存时间,超过这个时间的连接将由连接池自动断开丢弃掉。当然正在使用的连接不会马上断开,而是等待它close再断开。配置为0的时候则不会对连接的生存时间进行限制。默认值0

maxIdleTimeExcessConnections

这个配置主要是为了减轻连接池的负载,配置不为0,则会将连接池中的连接数量保持到minPoolSize,为0则不处理。

配置Prepared

Statement缓存(扩展)

maxStatements

连接池为数据源缓存的PreparedStatement的总数。由于PreparedStatement属于单个Connection,所以这个数量应该根据应用中平均连接数乘以每个连接的平均PreparedStatement来计算。为0的时候不缓存,同时maxStatementsPerConnection的配置无效。

maxStatementsPerConnection

连接池为数据源单个Connection缓存的PreparedStatement数,这个配置比maxStatements更有意义,因为它缓存的服务对象是单个数据连接,如果设置的好,肯定是可以提高性能的。为0的时候不缓存。


1.2.5    编写工具类

C3P0提供核心工具类:ComboPooledDataSource,如果要使用连接池,必须创建该类的实例对象。

  • new ComboPooledDataSource(“名称”); 使用配置文件“命名配置”

          <named-config name="itcast">

  • new ComboPooledDataSource(); 使用配置文件“默认配置”

          <default-config>

数据库连接池C3P0,DBCP教程详解示例

public class C3P0Utils{
   //使用默认配置
//  privatestatic ComboPooledDataSource dataSource = new ComboPooledDataSource();
   //使用命名配置
   private static ComboPooledDataSource dataSource = new ComboPooledDataSource("itheima");
   /**
    * 获得数据源(连接池)
    * @return
    */

   public static DataSource getDataSource(){
       returndataSource;
   }
   /**
    * 获得连接
    * @return
    * @throws SQLException
    */

   public static Connection getConnection(){
       try {
           returndataSource.getConnection();
       }catch (Exception e) {
           thrownew RuntimeException(e);
       }
   }
} 

1.3     DBCP连接池

DBCP也是一个开源的连接池,是Apache Common成员之一,在企业开发中也比较常见,tomcat内置的连接池。

1.3.1    导入jar

数据库连接池C3P0,DBCP教程详解示例

1.3.2    核心类

@Test
public void demo01() throws Exception{
   //1 获得连接池
   BasicDataSource dataSource = new BasicDataSource();
   //1.1 基本项
   dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  dataSource.setUrl("jdbc:mysql://localhost:3306/webdb_4");
   dataSource.setUsername("root");
   dataSource.setPassword("root");
   //1.2 其他项
   // * 初始化连接池中连个的个数
   dataSource.setInitialSize(5);
   // * 最大活动数
   dataSource.setMaxActive(10);
   //2获得连接
   Connectionconn = dataSource.getConnection();
   System.out.println(conn);
}

1.3.3    配置文件

  • 配置文件名称:*.properties

  • 配置文件位置:任意,建议src(classpath/类路径)

  • 配置文件内容:properties不能编写中文,不支持在STS中修改,必须使用记事本修改内容,否则中文注释就乱码了

#连接设置

driverClassName=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/webdb

username=root

password=root

#<!-- 初始化连接 -->

initialSize=10

#最大连接数量

maxActive=50

#<!-- 最大空闲连接 -->

maxIdle=20

#<!-- 最小空闲连接 -->

minIdle=5

#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60 -->

maxWait=60000


#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]

#注意:"user""password" 两个属性会被明确地传递,因此这里不需要包含他们。

connectionProperties=useUnicode=true;characterEncoding=gbk

 

#指定由连接池所创建的连接的自动提交(auto-commit)状态。

defaultAutoCommit=true

 

#driver default 指定由连接池所创建的连接的只读(read-only)状态。

#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix

defaultReadOnly=

 

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。

#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED,READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE

defaultTransactionIsolation=READ_UNCOMMITTED

 

1.3.4    常见配置项

分类

属性

描述

必须项

driverClassName


url


username


password


基本项

maxActive

最大连接数量

minIdle

最小空闲连接

maxIdle

最大空闲连接

initialSize

初始化连接




优化配置(扩展)

logAbandoned

连接被泄露时是否打印

removeAbandoned

是否自动回收超时连接

removeAbandonedTimeout

超时时间(以秒数为单位)

maxWait

超时等待时间以毫秒为单位 1000等于60

timeBetweenEvictionRunsMillis

在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位

numTestsPerEvictionRun

在每次空闲连接回收器线程(如果有)运行时检查的连接数量

minEvictableIdleTimeMillis

连接在池中保持空闲而不被空闲连接回收器线程

参考文档:http://commons.apache.org/proper/commons-dbcp/configuration.html


1.3.5    编写工具类

public class DBCPUtils{
   private static DataSource dataSource;
   static{
       try {
           //1加载配置文件,获得文件流
           InputStreamis =DBCPUtils.class.getClassLoader().getResourceAsStream("dbcp.properties");
           //2使用Properties处理配置文件
           Propertiesprops = new Properties();
           props.load(is);
           //3使用工具类创建连接池(数据源)
           dataSource= BasicDataSourceFactory.createDataSource(props);
       }catch (Exception e) {
           thrownew RuntimeException(e);
       }
   }
   public static DataSource getDataSource(){
       returndataSource;
   }
   public static Connection getConnection(){
       try {
           return  dataSource.getConnection();
       }catch (Exception e) {
           thrownew RuntimeException(e);

       }

   }

}
1.4    自定义连接池

1.4.1    案例分析

根据我们对连接池简单的理解,如果我们要编写自定义连接池,需要完成以下步骤

1.创建连接池实现(数据源),并实现接口 javax.sql.DataSource 。因为我们只使用该接口中getConnection()方法,简化本案例,我们将自己提供方法,而没有实现接口

2.提供一个集合,用于存放连接,因为移除/添加操作过多,所以选择LinkedList

3.本案例在静态代码块中,为连接池初始化3个连接。

4.之后程序如果需要连接,调用实现类的getConnection(),本方法将从连接池(容器List)获得连接。为了保证当前连接只能提供给一个线程使用,所以我们需要将连接先从连接池中移除。

5.当用户使用完连接,释放资源时,不执行close()方法,而是将连接添加到连接池中。

 

1.4.2    案例实现

1.4.2.1   提供容器及初始化

//#1 创建容器,用于存放连接Connection
private static LinkedList<Connection> pool =new LinkedList<Connection>();
//#1.1初始化连接池中的连接
static{
   try {
       //1 注册驱动
       Class.forName("com.mysql.jdbc.Driver");
       for(int i = 0; i < 3; i++) {
           //2获得连接
           Connectionconn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day10_db","root", "1234");
           //3将连接添加到连接池中
           pool.add(conn);
       }
   } catch(Exception e) {
       thrownew RuntimeException(e);
   }
}

1.4.2.2   获得连接

/**
* #2 获得连接,从连接池中获得连接
* @return
*/

public static Connection getConnection(){
  returnpool.removeFirst();
}
1.4.2.3   归还连接
/**
* #3 释放资源,当链接connection close时,归还给连接池
* @paramconn
* @param st
* @param rs
*/

public static void release(Connection conn){
   try {
       if(conn != null) {
//          conn.close();   //不是真的关闭
           pool.add(conn); //将从连接池获得连接,归还给连接池
       }
   } catch(Exception e) {
   }
}

1.4.2.4   测试使用

为了体现连接池优势,我们将采用多线程并发访问,使同一个连接在不同的时段,被不同的线程使用。

public class TestCustomPool {
   public static void main(String[] args) {
       //1 获得连接
           Connectionconn = JdbcUtils.getConnection();
           System.out.println("使用:" + conn + " , " +Thread.currentThread());
           //2释放资源
           JdbcUtils.release(conn);
   }
}

1.5    自定义连接池:方法增强

1.5.1    需求

自定义连接池中存在严重问题,用户调用getConnection()获得连接后,必须使用release()方法进行连接的归还,如果用户调用 conn.close() 将连接真正的释放,连接池中将出现无连接可用。

此时我们希望,即使用户调用了close()方法,连接仍归还给连接池。close()方法原有功能时释放资源,期望功能:将当前连接归还连接池。说明close()方法没有我们希望的功能,我们将对close()方法进行增强,从而实现将连接归还给连接池的功能。


1.5.2    方法增强总结

1.继承,子类继承父类,将父类的方法进行复写,从而进行增强。

使用前提:必须有父类,且存在继承关系。

2.装饰者设计模式,此设计模式专门用于增强方法。

使用前提:必须有接口

缺点:需要将接口的所有方法都实现

3.动态代理:在运行时动态的创建代理类,完成增强操作。与装饰者相似

使用前提:必须有接口

难点:需要反射技术

 

1.5.3    装饰者设计模式

设计模式:专门为解决某一类问题,而编写的固定格式的代码。

装饰者固定结构:接口A,已知实现类C,需要装饰者创建代理类B

1.创建类B,并实现接口A

2.提供类B的构造方法,参数类型为A,用于接收A接口的其他实现类(C

3.给类B添加类型为A成员变量,用于存放A接口的其他实现类

4.增强需要的方法

5.实现不需要增强的方法,方法体重调用成员变量存放的其他实现类对应的方法

A a = …C;
B b = new B(a);
class B implements A{
 private Aa;
 public B(Aa){
    this.a =a;
}
//增强的方法
public void close(){
}
 //不需要增强的方法
 public voidcommit(){
  this.a.commit();
}
}

 

1.5.4    实现

1.5.4.1   装饰类

数据库连接池C3P0,DBCP教程详解示例


数据库连接池C3P0,DBCP教程详解示例

 

public class MyConnection implements Connection {
   private Connection conn;
   private List<Connection> pool;
   public MyConnection(Connection conn){
       this.conn= conn;
   }

   /* 因为与自定义连接池有关系,所以需要另外添加一个构造方法 */

   public MyConnection(Connection conn,List<Connection> pool){
       this.conn= conn;
       this.pool= pool;
   }
   /* 以下是增强的方法 */
   @Override
   public void close() throws SQLException {
       //将调用当前close的链接Connection对象添加到链接池中
//      System.out.println("连接归还:" + this);
       this.pool.add(this);
   }
   /* 以下是不需要增强的方法  */

   @Override
   public void commit() throws SQLException {
       this.conn.commit();
   }
   ....
}

 

1.5.4.2   使用装饰类(包装类)

将由DriverManager创建的连接,使用装饰类包装一下,然后添加到连接池中,构造方法中将容器pool传递进去,方便连接的归还。

数据库连接池C3P0,DBCP教程详解示例

1.5.4.3   使用连接

数据库连接池C3P0,DBCP教程详解示例

 


记得分享给身边有需要的人

小编微信:xxf960326

推荐阅读目录

⊙ 

⊙  

   

 

推荐Java学习小程序


小编的微信


以上是关于数据库连接池C3P0,DBCP教程详解示例的主要内容,如果未能解决你的问题,请参考以下文章

数据库连接池优化配置(druid,dbcp,c3p0)

dbcp,c3p0连接池

DBCP,C3P0与Tomcat jdbc pool 连接池的比较

DataSource--DBCP--C3P0--DBUtils

[转]MySQL连接池配置详解(DBCP)

JDBC学习笔记——数据库连接池(dbcp&C3P0)