您当前的位置: 首页 >  数据库

梁云亮

暂无认证

  • 2浏览

    0关注

    1211博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

数据库连接池技术 之 C3P0

梁云亮 发布时间:2021-06-24 14:29:44 ,浏览量:2

简介

数据库连接池C3P0框架是个非常优异的开源类库,它根据JDBC3规范和JDBC2规范的标准扩展部分定义实现,使得传统的JDBC更适合企业级开发。在0.9.5版本中,C3P0完全支持JDBC4规范。 C3P0能够高性能的管理数据源,它提供了如下几个有用的服务:

  • 获取数据库连接的方式。由传统的基于DriverManager的JDBC驱动获取转换为新的javax.sql.DataSource模式获取。
  • 将连接池和PreparedStatement隐藏在DataSource后面。DataSource可以"包装"传统的驱动或者是任何不带连接池的DataSource。

C3P0库在以下几方面表现优秀:

  • C3p0数据源都是Referenceable(可引用的)和Serializable(可序列化的),因此适合绑定基于JNDI的命名服务。
  • 当把从连接池中取出的Connection和Statement放回连接池的时候,Statement和ResultSet将被仔细的清理,用来预防因懒惰采用仅仅清理Connection的资源管理策略而导致的资源耗尽的情况发生。
  • C3p0库采用由JDBC2和JDBC3规范定义的方法。
C3P0有三种方式实现: 1. 在类路径下配置一个名称为cfg.properties的属性文件,内容如下:
driverClass=xxx
jdbcUrl=xxx
user=xxx
password=xxx

然后代码中实现:

Properties props = new Properties();
InputStream in = Thread.class.getResourceAsStream("cfg.properties");
props.load(in);
in.close();
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass(props.getProperty("driverClass"));
cpds.setJdbcUrl(props.getProperty("jdbcUrl"));
cpds.setUser(props.getProperty("user"));
cpds.setPassword(props.getProperty("password"));

上面的属性文件也可以写成xml的形式:



	root
	xxx
	xxx
	xxx


	...


然后自己解析xml文件,这样可以实现多个数据源的配置。

2. 配置默认的属性文件

在类路径下提供一个c3p0.properties文件(不能改名),配置如下:

c3p0.driverClass=com.mysql.jdbc.Driver  #驱动
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/jdbc  #地址
c3p0.user=root  #用户名
c3p0.password=lovejava  #密码  
c3p0.initialPoolSize=6  #连接池初始化时创建的连接数  
c3p0.minPoolSize=3  #连接池保持的最小连接数
c3p0.acquireIncrement=3  #连接池在无空闲连接可用时一次性创建的新数据库连接数,默认值为3
#连接池中拥有的最大连接数,如果获得新连接时会使连接总数超过这个值则不会再获取新连接,而是等待其他连接释放,所以这个值有可能会设计地很大,默认值为15  
c3p0.maxPoolSize=15  
#连接的最大空闲时间,单位秒。如果超过这个时间,某个数据库连接还没有被使用,则会断开掉这个连接 
c3p0.maxIdleTime=100  
#连接池在获得新连接失败时重试的次数,如果小于等于0则无限重试直至连接获得成功  
c3p0.acquireRetryAttempts=30  
c3p0.acquireRetryDelay=1000    #连接池在获得新连接时的间隔时间  
...

上面只提供了最基本的配置项,其他配置项参照文档配置,记得是c3p0.后面加属性名就是了,最后初始化数据源的方式就是这样简单:

DataSource  ds = new ComboPooledDataSource();
return ds;

然后就可以使用数据源了,C3P0会对c3p0.properties进行自动解析的。

3. 在类路径下提供一个c3p0-config.xml文件

这种方式可以为多个数据源服务,提供default-config和named-config两种配置方式


	
		root
		java
		com.mysql.jdbc.Driver
		jdbc:mysql://localhost:3306/jdbc
		6
		30
		100
		10
	
	
		root
		java
		com.mysql.jdbc.Driver
		jdbc:mysql://localhost:3306/jdbc
		10
		30
		100
		10
	

在Java代码中,只需要通过如下语句就能获取到数据源了:

DataSource  ds = new ComboPooledDataSource("mySource");

注意: 使用连接池后,Connection还需要关闭,即仍然需要connection.close()方法。当然,这个close()最终执行的代码,并不是直接关闭物理连接,而是将其返回到连接池,以便后来者能继续使用。

示例:基于C3P0的JDBC工具类:
public class DBUtils {
    private static DataSource ds = null;
    //使用ThreadLocal存储当前线程中的Connection对象
private static ThreadLocal threadLocal = new 
										         ThreadLocal();
    static{    //在静态代码块中创建数据库连接池
        try{
            ds = new ComboPooledDataSource("mySource");//使用C3P0的命名配置创建数据源
        }catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }
    // 从数据源中获取数据库连接
    public static Connection getConnection() throws SQLException{
        Connection conn = threadLocal.get();//从当前线程中获取Connection
        if(conn==null){
            conn = getDataSource().getConnection();//从数据源中获取数据库连接
            threadLocal.set(conn); //将Connection绑定到当前线程
        }
        return conn;
    }
    public static void startTransaction(){ //开启事务
        try{
            Connection conn =  threadLocal.get();
            if(conn==null){
                conn = getConnection();
                threadLocal.set(conn);   //把 Connection绑定到当前线程上
            }
            conn.setAutoCommit(false);    //开启事务
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static void rollback(){ //回滚事务
        try{
            Connection conn = threadLocal.get();//从当前线程中获取Connection
            if(conn!=null){
                conn.rollback();  //回滚事务
            }
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static void commit(){ //提交事务
        try{
            Connection conn = threadLocal.get();   //从当前线程中获取Connection
            if(conn!=null){
                conn.commit();     //提交事务
            }
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static void close(){ //关闭连接(并不是真的关闭,而是把连接还给数据库连接池)
        try{
            Connection conn = threadLocal.get();   //从当前线程中获取Connection
            if(conn!=null){
                conn.close();  //----------①
                threadLocal.remove();//解除当前线程上绑定Connection
            }
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static DataSource getDataSource(){ //获取数据源
        return ds; //从数据源中获取数据库连接
    }
}

通过ComboPooledDataSource获取到的Connection是NewProxyConnection,该类重写了close()方法,所以编号①处不会直接释放关闭到物理连接,而是将其重新放回到连接池中。

关注
打赏
1665409997
查看更多评论
立即登录/注册

微信扫码登录

0.0408s