DBCP与C3P0连接池

目录

1 自定义连接池

1.1 什么是连接池?

1.2 自定义连接池

1.3 解决Connection.close方法释放连接问题

2 连接池工具

2.1 DBCP连接池     

2.2 C3P0连接池

3 元数据的使用

3.1 什么是元数据?

3.2 使用元数据


1 自定义连接池

1.1 什么是连接池?

        之前jdbc步骤: 获取连接 -> 得到Statement-> 发送sql -> 关闭连接

        问题: 获取连接对象需要消耗比较多的资源,而每次操作都要重新获取新的连接对象,执行一次操作就把连接关闭,这样连接对象的使用效率并不高!!!

        办法: 能不能让连接对象反复使用???如果可以的话,连接对象使用率提高!

        这就可以用连接池实现!!

1.2 自定义连接池

        自定义连接池实现:

        1)连接池中初始化若干个连接对象

        2)当连接池中连接不足,重新连接数据库获取新的连接对象

        3)总连接对象不能超过最大连接数

/**

 * 自定义的连接池

 */

public class MyPool {

   //连接参数

   private static String url = "jdbc:mysql://localhost:3306/day19";

   private static String user = "root";

   private static String password = "root";

   private static String driverClass = "com.mysql.jdbc.Driver";

   //使用集合存储多个连接对象

   LinkedList<Connection> pool = new LinkedList<Connection>();

   /**

    * 连接池的初始连接数

    */

   private int initSize = 5;

   /**

    * 连接池的最大连接数

    */

   private int maxSize = 8;

   /**

    * 连接池中的当前连接数,用于记录连接中有几个连接对象?

    */

   private int currentSize = 0;

  

   public MyPool(){

      /**

       * 创建若干个连接对象,放入到集合中

       */

      for(int i=1;i<=initSize;i++){

          pool.addLast(createConnection());

          currentSize++;

      }

   }

  

   static{

      try {

          //注册驱动

          Class.forName(driverClass);

      } catch (ClassNotFoundException e) {

          e.printStackTrace();

          throw new RuntimeException(e);

      }

   }

  

   /**

    * 创建连接方法

    */

   private Connection createConnection(){

      try {

          Connection conn = DriverManager.getConnection(url, user, password);

          return conn;

      } catch (SQLException e) {

          e.printStackTrace();

          throw new RuntimeException(e);

      }

   }

  

   /**

    * 对外提供获取连接的方法

    */

   public Connection getConnection(){

      /**

       * 1)判断连接池中是否还有连接对象,池中有连接,直接取出池中连接

       */

      if(pool.size()>0){

          /**

           * 直接返回连接池中的一个连接对象

           */

          return pool.removeFirst();

      }

     

      /**

       * 2)如果初始连接数不足的情况下,需要获取新的连接对象。但不能超过最大连接数

       */

      if(currentSize<maxSize){

          Connection conn = createConnection();

          currentSize++;

          return conn;

      }

     

      /**

       * 3)超过最大连接数时,需要处理(抛出异常或让用户等待)

       */

      throw new RuntimeException("超过了最大连接数,请稍后再来");

   }

  

   /**

    * 对外提供释放连接的方法

    */

   public void releaseConnection(Connection conn){

      /**

       * 把用完的连接对象放回到连接池中

       */

      pool.addLast(conn);

   }

}

1.3 解决Connection.close方法释放连接问题

1)静态代理:

        1.1 创建Connection接口的实现类(代理类)

        1.2 在代理类中,重写close方法

        注意: 使用静态代理,需要把原有对象的方法全部实现。

2)动态代理:

使用jdk自带的动态代理类Proxy类:

用于创建代理类对象方法

 static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

        参数一:类加载器,可以使用当前项目的任意类获取类加载器

        参数二:代理类需要实现的接口

         参数三: 指定代理类代理了之后要如何处理

 InvocationHandler接口: 代理类的处理程序接口

调用代理类对象的方法:

       Object invoke(Object proxy, Method method, Object[] args) 

              参数一:代理类对象实例

              参数二:当前正在调用哪个方法

                参数三:当前调用方法时传入的参数

如果以上自定义连接要拿到实际应用中使用,还需要不断优化。

                 1)比如线程并发问题

                 2)达到最大连接数应该先等待,再抛出异常

                 3)当连接空闲超过一定时间,连接池要回收连接

                 ....

        所以这时就使用别人写的连接池工具!!

2 连接池工具

2.1 DBCP连接池     

        DBCP: DataBase Connection Pool

        特点:

                 1)Apache旗下的软件,开源连接池
                 2)Tomcat的服务器的连接池默认实现

        使用步骤:

                 1)导入dbcpjar

                         commons-dbcp-1.4.jar  核心包

                         commons-pool-1.5.6.jar 辅助包

                 2)创建连接池对象BasicDataSource对象

                 3)设置连接参数(urluserpassworddirverClass

                 4)设置连接池参数(初始连接数,最大连接数,最大等待时间)

                 5)获取连接对象(getConnection() 方法)

@Test

   public void test1(){

      try {

          //1.创建连接池对象

          BasicDataSource ds = new BasicDataSource();

          //2.设置连接参数

         ds.setUrl("jdbc:mysql://localhost:3306/day19");

          ds.setUsername("root");

          ds.setPassword("root");

         ds.setDriverClassName("com.mysql.jdbc.Driver");

         

          //3.设置连接池参数

          ds.setInitialSize(5);//初始连接数

          ds.setMaxActive(8);//最大连接数

          ds.setMaxWait(3000);//超过最大连接数时,最大等待时间

          ds.setMaxIdle(3000);//最大空闲时间

         

          //4.获取连接

          for(int i=1;i<=9;i++){

             Connection conn = ds.getConnection();

             System.out.println(conn.hashCode());

             if(i==5){

                //释放连接(不是真正的关闭连接对象,而是把连接对象放回连接池)

                conn.close();

             }

          }

      } catch (SQLException e) {

          e.printStackTrace();

      }

   }

使用配置文件加载

1)配置文件(dbcp.properties)

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

username=root

password=root

driverClassName=com.mysql.jdbc.Driver

         

initialSize=5

maxActive=8

maxWait=3000

maxIdle=3000

2)程序

@Test

   public void test2(){

      try {

          Properties prop = new Properties();

         prop.load(Demo.class.getResourceAsStream("/dbcp.properties"));

          //1.创建连接池对象

          BasicDataSource ds = (BasicDataSource)BasicDataSourceFactory.createDataSource(prop);

         

          //2.获取连接

          for(int i=1;i<=9;i++){

             Connection conn = ds.getConnection();

             System.out.println(conn.hashCode());

             if(i==5){

                //释放连接(不是真正的关闭连接对象,而是把连接对象放回连接池)

                conn.close();

             }

          }

      }catch (Exception e) {

          e.printStackTrace();

      }

   }

2.2 C3P0连接池

特点:

                1)开源连接池

                2)Hibernate框架,默认推荐使用C3P0作为连接池实现

        使用步骤:

                 1)导入c3p0jar

                         c3p0-0.9.1.2.jar 核心包

                 2)创建连接池对象ComboPooledDataSource对象

                 3)设置连接参数(urluserpassworddirverClass

                 4)设置连接池参数(初始连接数,最大连接数,最大等待时间)

                 5)获取连接对象(getConnection() 方法)

/**

 * 使用C3p0连接池

* 注意: DataSource接口是Sun公司设计的用于规范连接池实现的接口。

 */

public class Demo {

   @Test

   public void test1(){

      try {

          //1.创建连接池对象

          ComboPooledDataSource ds = new ComboPooledDataSource();

          //2.设置连接参数

          ds.setDriverClass("com.mysql.jdbc.Driver");

         ds.setJdbcUrl("jdbc:mysql://localhost:3306/day19");

          ds.setUser("root");

          ds.setPassword("root");

         

          //3.设置连接池参数

          ds.setInitialPoolSize(5);// 初始化连接数

          ds.setMaxPoolSize(8);//最大连接数

          ds.setCheckoutTimeout(3000);//最大等待时间

         

          //4.获取连接

          for(int i=1;i<=9;i++){

             Connection conn = ds.getConnection();

             System.out.println(conn);

             if(i==5){

                /**

                 * 把连接对象放回连接池

                 */

                conn.close();

             }

          }

         

      } catch (Exception e) {

          e.printStackTrace();

      }

   }

  

   /**

    * 使用配置文件方式读取参数信息

    * 注意: c3p0会默认查询类路径的c3p0-config.xml文件,文件名不能错!!

    */

   @Test

   public void test2(){

      try {

          //1.创建连接池对象(方式一: 使用默认配置(default-config))

          //ComboPooledDataSource ds = new ComboPooledDataSource();

         

          //2.创建连接池对象(方式二: 使用命名配置(named-configmysql_day18))

          ComboPooledDataSource ds = new ComboPooledDataSource("mysql_day18");

         

          //2.获取连接

          for(int i=1;i<=9;i++){

             Connection conn = ds.getConnection();

             System.out.println(conn);

             if(i==5){

                /**

                 * 把连接对象放回连接池

                 */

                conn.close();

             }

          }

      } catch (SQLException e) {

          e.printStackTrace();

      }

   }

}

3 元数据的使用

3.1 什么是元数据?

        希望知道以下:

                 1)数据库相关的信息:(封装到数据库元对象: DataBaseMetaData)

                                  数据库的版本

                                 驱动程序的版本

                 2)参数相关的信息:(封装到参数元对象:ParameterMetaData)

                                  参数数量

                                  参数类型

                 3)结果相关的信息:(封装到结果集元对象: ResultSetMetaData)

                                  列数量

                                  列名称

        jdbc步骤:

                 1)连接数据库,获取Connection对象  (得到DataBaseMetaData)

                 2)创建Statment,预编译sql语句 (得到ParameterMetaData)

                 3)设置参数

                 4)执行sql,返回结果集 (得到ResultSetMetaData)

                 5)遍历结果集

                 6)关闭连接

        练习:

                 抽取两个通用的jdbc方法

                 1)通用的修改方法(insert、update、delete)

                         update()  用于任何表的任何更新操作

                 2)通用的查询方法,查询后返回List集合

                         find()  无论查询什么表,都能返回我们需要的List集合

3.2 使用元数据

/**

 * jdbc的工具方法

 */

public class DBUtil {

        private static ComboPooledDataSource ds = new ComboPooledDataSource();

        /**

         * 通用的更新方法

         * 不同更新操作的不同点:

         *   1)sql语句不同

         *  2)参数列表不同

         */

        public static void update(String sql,Object[] values){

                 Connection conn = null;

                 PreparedStatement stmt = null;

                 try {

                         //获取连接

                         conn = ds.getConnection();

                         //预编译sql

                         stmt = conn.prepareStatement(sql);

                         //设置参数

                         ParameterMetaData md = stmt.getParameterMetaData();

                         //得到参数数量

                         int count = md.getParameterCount();

                         if(values!=null){

                                  for(int i=1;i<=count;i++){

                                          stmt.setObject(i, values[i-1]);

                                  }

                         }

                         //执行sql

                         stmt.executeUpdate();

                 } catch (SQLException e) {

                         e.printStackTrace();

                         throw new RuntimeException(e);

                 } finally{

                         if(stmt!=null)

                                  try {

                                          stmt.close();

                                  } catch (SQLException e) {

                                          e.printStackTrace();

                                          throw new RuntimeException(e);

                                  }

                         if(conn!=null)

                                  try {

                                          conn.close();

                                  } catch (SQLException e) {

                                          e.printStackTrace();

                                          throw new RuntimeException(e);

                                  }

                 }

        }

        /**

         * 通用的查询方法

         * 不同点:

         *     1)sql语句不同

         *     2)参数不同

         *     3)List集合中的对象不同

         */

        public static List find(String sql,Object[] values,Class clazz){

                 Connection conn = null;

                 PreparedStatement stmt = null;

                 ResultSet rs = null;

                 List list = new ArrayList();

                 try {

                         //获取连接

                         conn = ds.getConnection();

                         //预编译sql

                         stmt = conn.prepareStatement(sql);

                         //设置参数

                         ParameterMetaData md = stmt.getParameterMetaData();

                         int count = md.getParameterCount();

                         if(values!=null){

                                  for(int i=1;i<=count;i++){

                                          stmt.setObject(i, values[i-1]);

                                  }

                         }

                         //执行sql

                         rs = stmt.executeQuery();

                         //得到结果集的元数据

                         ResultSetMetaData rsmd = rs.getMetaData();

                         //得到列数据

                         int columnCount = rsmd.getColumnCount();

                         //遍历结果集

                         while(rs.next()){

                                  //创建一个javabean对象

                                  Object obj = clazz.newInstance();

                                  //把每行的结果放入javabean对象

                                  //遍历每列

                                  for(int i=1;i<=columnCount;i++){

                                          //得到列名称

                                          String columnName = rsmd.getColumnName(i);

                                          //得到列内容

                                          Object value = rs.getObject(columnName);

                                          //把列内容赋值给javabean

                                          /**

                                           * 约定前提: 数据库表的字段名称和javabean的属性名称保持一致!!!!

                                           */

                                          BeanUtils.copyProperty(obj, columnName, value);

                                  }

                                  //把javabean放入list集合 

                                  list.add(obj);

                         }

                         return list;

                 } catch (Exception e) {

                         e.printStackTrace();

                         throw new RuntimeException(e);

                 } finally{

                         if(stmt!=null)

                                  try {

                                          stmt.close();

                                  } catch (SQLException e) {

                                          e.printStackTrace();

                                          throw new RuntimeException(e);

                                  }

                         if(conn!=null)

                                  try {

                                          conn.close();

                                  } catch (SQLException e) {

                                          e.printStackTrace();

                                          throw new RuntimeException(e);

                                  }

                 }

        }

}

  • 23
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我会回答你的问题,以下是常用数据库连接池 DBCPc3p0、Druid 的配置说明: 1. DBCP (Apache Commons DBCP) DBCP 是 Apache Commons 项目中的一个子项目,它是一个纯 Java 实现的数据库连接池DBCP 的使用非常简单,只需要引入相关的 jar 包即可。以下是 DBCP 的配置说明: ``` # 最大连接数 maxActive=100 # 最大空闲连接数 maxIdle=30 # 最小空闲连接数 minIdle=10 # 获取连接时的最大等待时间,单位为毫秒 maxWait=10000 # 是否开启自动回收空闲连接的线程 removeAbandoned=true # 回收超时时间,单位为秒 removeAbandonedTimeout=180 # 是否开启缓存 PreparedStatement,提高性能 poolPreparedStatements=true # 缓存 PreparedStatement 的最大数量 maxOpenPreparedStatements=100 ``` 2. c3p0 c3p0 是一个开源的 JDBC 数据库连接池,它实现了数据源和 JNDI 绑定,支持 JDBC3 的 Connection 和 Statement 缓存以及 JDBC4 的自动化管理。以下是 c3p0 的配置说明: ``` # 最大连接数 c3p0.maxPoolSize=100 # 最小连接数 c3p0.minPoolSize=10 # 初始化连接数 c3p0.initialPoolSize=10 # 获取连接时的最大等待时间,单位为毫秒 c3p0.checkoutTimeout=10000 # 是否自动回收超时连接 c3p0.autoCommitOnClose=true # 是否开启自动回收空闲连接的线程 c3p0.idleConnectionTestPeriod=60 # 回收超时时间,单位为秒 c3p0.maxIdleTime=1800 # 是否开启缓存 PreparedStatement,提高性能 c3p0.cachePreparedStatements=true # 缓存 PreparedStatement 的最大数量 c3p0.maxStatements=100 ``` 3. Druid Druid 是阿里巴巴开源的一个高性能、可扩展、功能强大的数据库连接池。它主要提供了以下功能:监控统计、防御 SQL 注入、批量处理、数据源加密、日志记录等。以下是 Druid 的配置说明: ``` # 最大连接数 druid.maxActive=100 # 最大空闲连接数 druid.maxIdle=30 # 最小空闲连接数 druid.minIdle=10 # 获取连接时的最大等待时间,单位为毫秒 druid.maxWait=10000 # 是否开启自动回收空闲连接的线程 druid.removeAbandoned=true # 回收超时时间,单位为秒 druid.removeAbandonedTimeout=180 # 是否开启缓存 PreparedStatement,提高性能 druid.poolPreparedStatements=true # 缓存 PreparedStatement 的最大数量 druid.maxOpenPreparedStatements=100 # 是否开启 SQL 执行监控 druid.stat=true # 是否开启防御 SQL 注入功能 druid.filters=stat,wall,log4j ``` 以上就是常用数据库连接池 DBCPc3p0、Druid 的配置说明。希望对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

棉花糖老丫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值