mysql笔记八——开源数据库连接池DBCP和C3P0的使用

DBCP数据库连接池

  • DBCP 是 Apache 软件基金组织下的开源连接池实现,使用DBCP数据源,应用程序应在系统中增加如下两个 jar 文件:
    Commons-dbcp.jar:连接池的实现 Commons-pool.jar:连接池实现的依赖库 Tomcat
    的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。

  • 核心代码

static{
    InputStream in = JdbcUtil.class.getClassLoader().
            getResourceAsStream("dbcpconfig.properties");
    Properties prop = new Properties();
    prop.load(in);

    BasicDataSourceFactory factory = new BasicDataSourceFactory();
    dataSource = factory.createDataSource(prop);
}
  • 我的代码示例
package dpcpPoolUse;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.junit.Test;

public class DbcpPoolDemo {

    @Test
    public void testDbcp() throws SQLException, InterruptedException{
        //      DataSource pool=new BasicDataSource();//不能用DataSource,因为里面没有set。。函数
        BasicDataSource pool=new BasicDataSource();//创建一个池对象
        pool.setDriverClassName("com.mysql.jdbc.Driver");
        pool.setUrl("jdbc:mysql://127.0.0.1:3306/sstud?useUnicode=true&characterEncoding=utf-8");
        pool.setUsername("root");
        pool.setPassword("1234");

        System.out.println(pool.getDefaultCatalog());//获取默认参数
        System.out.println(pool.getInitialSize());//获取连接池初始化大小
        //      System.out.println(pool.getLoginTimeout());//登录限制时间
        System.out.println(pool.getMaxWait());//pool最长等待时间(-1)
        System.out.println(pool.getMaxIdle());最大空闲时间。如果一个用户获取一个连接,不用,多长时间会被强行收回
        System.out.println(pool.getMaxActive());//pool最多获得数
        System.out.println("__________________");
        //自己设置参数
        //      pool.setMaxWait(1);
        //      pool.setMaxIdle(1);
        pool.setMaxActive(20);
        for(int i=0;i<20;i++){
            //          Thread.sleep(1100);
            Connection con=pool.getConnection();//优先拿到刚刚使用过得
            System.out.println(i+":::::::::::"+con.hashCode());
            //          con.close();
        }
    }
    //通过配置文件  读取
    @Test
    public void testPropertyFile() throws Exception{
        Properties p=new Properties();
        //      p.load(ClassLoader.getSystemClassLoader().getSystemResourceAsStream("dpcp.properities"));//配置文件要放在src(bin)的根目录---classpath的根
        p.load(DbcpPoolDemo.class.getResourceAsStream("dbcp.properities"));//配置文件和当前类的class放在一起
        DataSource pool=BasicDataSourceFactory.createDataSource(p);//DataSource要通过配置文件读取
        //DataSource 不能进行常规设置
        //从它的池中获取连接(8个)
        for(int i=0;i<10;i++){
            Connection con=pool.getConnection();
            System.out.println(i+":::::"+con.hashCode());
            if((i&1)==0){
                con.close();
            }
        }
    }
}
  • 连接池DbcpUtil工具
package dpcpPoolUse;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;

public class DbcpUtil {
    private static DataSource pool=null;
//  static BasicDataSource pool=new BasicDataSource();//创建一个池对象
    private static ThreadLocal<Connection> tl=new ThreadLocal<Connection>();
    static{
        Properties p=new Properties();
        try { 
//          pool.setDriverClassName("com.mysql.jdbc.Driver");
//          pool.setUrl("jdbc:mysql://127.0.0.1:3306/sstud?useUnicode=true&characterEncoding=utf-8");
//          pool.setUsername("root");
//          pool.setPassword("1234");
             Class.forName("com.mysql.jdbc.Driver");//需要自己写
            p.load(DbcpPoolDemo.class.getResourceAsStream("dbcp.properities"));//配置文件和当前类的class放在一起
            System.out.println(p);
            pool=BasicDataSourceFactory.createDataSource(p);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //返回DataSource--池
       public static DataSource getDataSource(){
           return pool;
       }

    public static ThreadLocal<Connection> getTl() {
        return tl;
    }

    public static void setTl(Object object) {
        DbcpUtil.tl = (ThreadLocal<Connection>) object;
    }

    public static Connection getCon(){
        Connection con=tl.get();
        if(con==null){
            try {
                con=pool.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            tl.set(con);
        }
        return con;
    }
    public static void main(String[] args) {
        System.out.println(getCon());
    }

}

C3P0数据库连接池

注意: c3p0拿到的连接因为每次增删改都会调用con.close()方法,所有每次拿到的是不同连接

  • C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
  • 和DPCP的区别:
    1).dbcp没有自动回收空闲连接的功能
    2).c3p0有自动回收空闲连接功能

  • C3p0需要的包和文件:c3p0-0.9.1.2.jar,没有更新
    配置文件c3p0-config.xml

c3p0-config.xml

<c3p0-config>
    <!-- 默认配置,如果没有指定则使用这个配置 -->
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">
            <![CDATA[jdbc:mysql://127.0.0.1:3306/mydb?useUnicode=true&characterEncoding=UTF-8]]>
        </property>
        <property name="user">root</property>
        <property name="password">1234</property>
        <!-- 初始化池大小 -->
        <property name="initialPoolSize">2</property>
        <!-- 最大空闲时间 -->
        <property name="maxIdleTime">30</property>
        <!-- 最多有多少个连接 -->
        <property name="maxPoolSize">10</property>
        <!-- 最少几个连接 -->
        <property name="minPoolSize">2</property>
        <!-- 每次最多可以执行多少个批处理语句 -->
        <property name="maxStatements">50</property>
    </default-config> 
    <!-- 命名的配置 -->
    <named-config name="hncu">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/mydb</property>
        <property name="user">root</property>
        <property name="password">1234</property>
        <property name="acquireIncrement">5</property><!-- 如果池中数据连接不够时一次增长多少个 -->
        <property name="initialPoolSize">100</property>
        <property name="minPoolSize">50</property>
        <property name="maxPoolSize">1000</property>
        <property name="maxStatements">0</property>
        <property name="maxStatementsPerConnection">5</property> <!-- he's important, but there's only one of him -->
    </named-config>
</c3p0-config> 

C3p0主要是通过配置文件来读取妻子的数据,很多框架都支持,很好用
下面我来演示如何操作
1.纯Java方式操作

@Test//纯Java方法使用c3p0
    public void c3p0Test() throws SQLException, PropertyVetoException{
        ComboPooledDataSource pool=new ComboPooledDataSource();//空参数如果classpath下没有c3p0-config.xml配置文件需要自己设置,
        pool.setUser("root");
        pool.setDriverClass("com.mysql.jdbc.Driver");
        pool.setPassword("1234");
        pool.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/sstud?useUnicode=true&characterEncoding=utf-8");
        //设置属性可以在此调用pool.setters()方法对pool进行定制 
//      pool.setMaxPoolSize(20);//默认是15个,现在设置20个大小
        pool.setAcquireIncrement(5);//连接池中的连接耗尽的时候c3p0一次同时获取的连接数

        //跟dbcp不同之处,连接关闭之后,内存会被释放,下次取时会重新开(内存地址不共用)
        for(int i=0;i<30;i++){
            Connection con=pool.getConnection();//不会像dbcp一样优先使用最近的连接
            System.out.println(i+":"+con.hashCode());//原理和dbcp一样
            if((i&2)==1){
                con.close();
            }
        }
    }

2.利用配置文件来读取
注意: c3p0-config.xml配置文件需要放在项目根目录下

@Test//采用配置文件的方式使用c3p0
    public void C3p0PropertyDemo() throws SQLException, PropertyVetoException{
//      ComboPooledDataSource pool=new ComboPooledDataSource();
        //空参,自动到classpath目录下面加载“c3p0-config.xml”配置文件---配置文件的存储位置和名称必须是这样,且使用“默认配置”
        //加载“c3p0-config.xml”文件中定义的“hncu”这个配置元素
        ComboPooledDataSource pool=new ComboPooledDataSource("hncu");
        System.out.println(pool.getAcquireIncrement());
        for (int i = 0; i <200; i++) {
            Connection con = pool.getConnection();
            System.out.println(i+":"+con);
            if((i%2)==0){
                con.close();
            }
        }
    }
  • 下面是我做的c3p0Util数据库连接池(加工了),
    注意:如果是同一个客户端操作,连接关闭后要把THreadLocal设置为null也就是 tl.set(null),这样下个客户端就拿不到你的连接了
package c3p0PoolUse;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3p0Pool {
    private  static DataSource pool=new ComboPooledDataSource();//读取配置文件
    private static ThreadLocal<Connection> tl=new ThreadLocal<Connection>();
    public static Connection getCon() throws SQLException{
        Connection con =tl.get();
        if(con==null){
            con=pool.getConnection();
            tl.set(con);
        }
        return con;
    }
    public static DataSource getPool() {
        return pool;
    }
    public static ThreadLocal<Connection> getTl() {
        return tl;
    }

}

C3p0Pool最终版

package cn.hncu.c3p0;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;


import com.mchange.v2.c3p0.ComboPooledDataSource;
//我们的这个包装,只是为了把c3p0池做成让每个线程(客户端)获得的是同一个连接,方便做b/s框架下的事务
public class C3p0Pool {
   private static DataSource pool;
   private static ThreadLocal<Connection> t = new ThreadLocal<Connection>();
   static{
       pool = new ComboPooledDataSource();

   }

   public static DataSource getDataSource(){
       return pool;
   }
   private static Connection conn=null;
   public static Connection getConnection() throws SQLException{
       conn = t.get();
       Connection conn2=null;
       if(conn==null){
           conn = pool.getConnection();
           Object obj=Proxy.newProxyInstance(C3p0Pool.class.getClassLoader(), 
                    new Class[]{Connection.class},new InvocationHandler() {
                //proxy是代理后的对象(等价于返回的obj), method就是类反射中的方法对象, args是执行method方法所需的参数
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args)
                                throws Throwable {

                            if(method.getName().equalsIgnoreCase("close")&&(args==null||args.length==0)){
                                System.out.println("一次close方法");
                                 t.set(conn);
                                return null;
                            }
                            return method.invoke(conn, args);//其他方法就行放行
                        }
                    });
           conn2=(Connection) obj;//必须用两个不同对象
           return conn2;
       }else{
           return conn;
       }
   }

}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值