自定义数据库连接池

来源:互联网 发布:网络销售培训招生 编辑:程序博客网 时间:2024/05/22 05:02

一、基本步骤

1.创建集合存储即将要创建的数据库连接池

      数据库连接需要经常增删,而链表的增删速度比较快,在这里我们使用LinkedList

2.创建配置文件存储即将用到的数据库驱动地址,数据库地址,用户名和密码

      配置文件我们采用config.properties

3.为提高速度在静态代码块中创建多个数据库连接并将该链接存储到集合中

      数据库连接的创建步骤:

      a.注册数据库驱动

      b.创建数据库连接

4.创建回收连接用于存储使用完毕的连接

      将使用完毕的数据库连接再放回LinkedList中,而不是关闭。

二、详细文件信息

配置文件config.properties的内容:

  1: dataDriver=com.mysql.jdbc.Driver
  2: sqlUrl=jdbc:mysql://localhost:3306/day16
  3: user=root
  4: password=root

连接池类文件:

  1: package net.csing.pool;
  2: 
  3: import java.io.FileInputStream;
  4: import java.io.FileNotFoundException;
  5: import java.io.IOException;
  6: import java.sql.DriverManager;
  7: import java.util.LinkedList;
  8: import java.util.List;
  9: import java.util.Properties;
 10: 
 11: import com.sql.Connection;
 12: 
 13: /*
 14:  * 创建自定义数据库连接池。
 15:  */
 16: public class ConPool {
 17:   public ConPool(){}
 18:   
 19:   //采用linkedlist存储数据库连接,linkedlist底层为链表,与arralylist相比增删“数据库连”接速度更快。
 20:   private static List<Connection> list=new LinkedList<>();
 21:   private static Properties properties=new Properties();
 22:   public static void createConnection(){
 23:     try {
 24:       Connection connection=null;
 25:       //注册mysql数据库驱动。
 26:       Class.forName(properties.getProperty("dataDriver"));
 27:       //创建数据库连接;
 28:       connection=(Connection) DriverManager.getConnection(properties.getProperty("sqlUrl"),properties.getProperty("user"),properties.getProperty("password"));
 29:       list.add(connection);
 30:     } catch (Exception e) {
 31:       
 32:       e.printStackTrace();
 33:     }
 34:   }
 35:   /*
 36:    * 当类一旦加载即创建数据库连接池,此处默认创建连接池中连接的个数为5;
 37:    */
 38:   static{
 39:     try {
 40:       //文件的加载比较慢,我们直接将其放在静态代码块里面。
 41:       properties.load(new FileInputStream(ConPool.class.getClassLoader().getResource("config.properties").getPath()));
 42:     } catch (Exception e1) {
 43:       e1.printStackTrace();
 44:     }
 45:     for(int x=0;x<5;x++){
 46:       createConnection();
 47:     }
 48:   }
 49:   public Connection getConnection(){
 50:     //获取连接前进行判断,如果连接池中的连接没有了就创建3个。
 51:     if(list.size()==0){
 52:       for(int x=0;x<3;x++){
 53:         createConnection();
 54:       }
 55:     }
 56:     //此处采用remove的方式获取连接并将该连接从连接池中删除,可谓一举两得。
 57:     Connection connection= list.remove(0);
 58:     System.out.println("取得连接,剩下的连接数是:"+list.size());
 59:     return connection;
 60:   }
 61:   public void re2Pool(Connection connection) {
 62:     //数据库连接用完放到连接池时,需先判断连接是否已经被使用者删除或者关闭,此处只判断了是否删除。
 63:     if(connection!=null){
 64:       list.add(connection);
 65:       System.out.println("返回连接,剩下的连接数是:"+list.size());
 66:     }
 67:   }
 68: }
 69: 

测试数据库连接池:

  1: package net.csing.test;
  2: 
  3: import java.sql.SQLException;
  5: import net.csing.pool.ConPool;
  7: import org.junit.Test;
  9: import com.sqlConnection;
 10: import com.sql.PreparedStatement;
 11: import com.sql.ResultSet;
 12: public class test {
 13:   @Test
 14:   public void getData() {
 15:     //创建连接池对象。
 16:     ConPool pool=new ConPool();
 17:     //创建连接,传输器,和结果集。
 18:     Connection connection=null;
 19:     PreparedStatement statement=null;
 20:     ResultSet resultSet=null;
 21:     try {
 22:       String sql="select * from account where name=?";
 23:       //从连接池获取连接。
 24:       connection=pool.getConnection();
 25:       //创建预编译传输器对象,此处采用preparedStatement可防止sql注入攻击。
 26:       statement=(PreparedStatement) connection.prepareStatement(sql);
 27:       //设置sql命令中第一个?的参数。
 28:       statement.setString(1, "cs");
 29:       //禁用sql自带的事务机制,开启自定义事务,此处只是测试,由于只有一条sql命令,开启不开启么有多大影响。
 30:       connection.setAutoCommit(false);
 31:       resultSet=(ResultSet) statement.executeQuery();
 32:       //事务提交。
 33:       connection.commit();
 34:       while(resultSet.next()){
 35:         System.out.println(resultSet.getString("name")+":"+resultSet.getInt("money"));
 36:       }
 37:     } catch (SQLException e) {
 38:       e.printStackTrace();
 39:     }finally{
 40:       if(resultSet!=null){
 41:         try {
 42:           resultSet.close();
 43:         } catch (Exception e2) {
 44:           e2.printStackTrace();
 45:         }finally{
 46:           resultSet=null;
 47:         }
 48:       }
 49:       if(statement!=null){
 50:         try {
 51:           statement.close();
 52:         } catch (Exception e2) {
 53:           e2.printStackTrace();
 54:         }finally{
 55:           statement=null;
 56:         }
 57:       }
 58:       if(connection!=null){
 59:         try {
 60:           //关闭连接时采用自定义的数据库连接回收函数,将该连接放回连接池。
 61:           pool.re2Pool(connection);
 62:         } catch (Exception e2) {
 63:           e2.printStackTrace();
 64:         }
 65:       }
 66:     }
 67:   }
 68: }
 69: 

数据库结构及信息:

数据库结构及信息

在数据库连接池的测试代码中采用创建一个函数的方式将不用的数据库连接回收到集合中,但在实际应用中我们通常采用的是connection.close()的方式关闭数据库连接,我们可以将此处进行改造,使其调用connection.close()方法时将不用的连接回收到集合中而不是真的关闭。

将原getConnection()进行如下改造:

  1: public Connection getConnection(){
  2:     //获取连接前进行判断,如果连接池中的连接没有了就创建3个。
  3:     if(list.size()==0){
  4:       for(int x=0;x<3;x++){
  5:         createConnection();
  6:       }
  7:     }
  9:     //此处采用remove的方式获取连接并将该连接从连接池中删除,可谓一举两得。
 10:     final Connection connection= list.remove(0);
 11:     Connection proxy=(Connection) Proxy.newProxyInstance(connection.getClass().getClassLoader(), 
 12:         connection.getClass().getInterfaces(), 
 13:         new InvocationHandler() {
 14:           @Override
 15:           public Object invoke(Object proxy, Method method, Object[] args)
 16:               throws Throwable {
 17:             if("close".equals(method.getName())){
 19:               re2Pool(connection);
 20:               return null;
 21:             }else {
 23:               return method.invoke(connection, args);
 24:             }
 25:           }
 26:         });
 28:     return proxy;
 29:   }

同时在关闭资源中connect连接的部分,我们可以直接采用如下的方式:

  1: if(connection!=null){
  2:         try {
  3:           //此处通过动态代理将close()的操作指向了re2Pool()函数将连接回收。
  4:           connection.close();
  5:         } catch (Exception e2) {
  6:           e2.printStackTrace();
  7:         }finally{
  8:           connection=null;
  9:         }
 10:       }

事实上我们可以直接采用开源数据库连接池C3P0进行连接,该方式更简单。

在库文件中导入C3P0的jar包,然后简单的进行如下配置即可使用C3P0的连接池。

  1:       ComboPooledDataSource cpds=new ComboPooledDataSource();
  2:       //通过以下步骤设置数据库驱动,数据库连接地址、用户名和密码。
  3:       cpds.setDriverClass("com.mysql.jdbc.Driver");
  4:       cpds.setJdbcUrl("jdbc:mysql://localhost:3306/day16");
  5:       cpds.setUser("root");
  6:       cpds.setPassword("root");
  7:       //设置上述操作后可以直接建立连接。
  8:       Connection connection = cpds.getConnection();

除了上述的配置方法外,C3P0还提供了另外一种更简单的配置方法,根据C3P0的说明文档,C3P0默认情况下会自动在类的加载目录下寻找名称为"c3p0-config.xml"的配置文件,我们只需要创建该文件并配置相关项,随后在java文件中创建ComboPooledDataSource对象获取连接即可。

c3p0-config.xml配置信息:

  1: <?xml version="1.0" encoding="UTF-8"?>
  2: 
  3: <c3p0-config>
  4:   <default-config>
  5:     <property name="driverClass">com.mysql.jdbc.Driver</property>
  6:     <property name="jdbcUrl">jdbc:mysql://localhost:3306/day16</property>
  7:     <property name="user">root</property>
  8:     <property name="password">root</property>
  9:   </default-config>
 10: </c3p0-config>

其实上述配置系信息是将我们在java代码中的配置转移到了配置文件中,使用起来更加方便。

0 0