自定义一个简单连接池以及常见连接池的使用

由于使用jdbc的时候,每操作一次都需要获取连接(创建),用完之后把连接释放掉了(销毁)。所以我们可以通过连接池来优化curd操作。

作用:管理数据库的连接,提高项目的性能。

思路:就是在连接池初始化的时候存入一定数量的连接,用的时候通过方法获取,不用的时候归还连接即可。注意:所有的连接池都必须实现javax.sql.DataSource接口。

获取连接方法:Connection getConnection()。

归还连接方法:connection.close();  //注意,这里会使用装饰者模式,让连接只是归还在了连接池中而不是真正的销毁。

下面我们开始自定义一个自己的连接池。

 1.初始化连接池。

  首先我们需要定义一个泛型为Connection的List集合,用来存放连接。在这里我们初始容量定义3个。

  然后通过JDBCUtills类来获取连接,并将连接放入List集合中。(关于JDBCUtils工具类的封装,见如下链接

public class MyDataSource {

        //初始化只需要一次就好,所以放在static静态代码块中
    static LinkedList<Connection> list = new LinkedList<>();
    
    static{
        //static不能抛异常,只能try...catch 
        try {
            for(int i = 0; i < 3; i++){
                Connection conn = JDBCUtils_plus.getConnection();
                list.add(conn);
            }
            
            
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

2.从连接池中获取连接

  先判断连接池是否为空,若为空,通过循环,创建新的连接放入连接池。若不为空,从List集合中取出第一个连接(removeFirst),然后j将连接返回。

  不过,这里通过装饰者模式包装了一个ConnectionWrapper类,包装类的作用是包装了Connection的close()方法,使得它不会销毁连接,只是将连接放回。

  关于ConnectionWrapper类的创建,后面会详述。

public static Connection getConnection(){
        if(list.isEmpty()){
            //如果为空,再获取连接进去
            for(int i = 0; i < 3;i++){
                try {
                    list.add(JDBCUtils_plus.getConnection());
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            
        }
        Connection conn = list.removeFirst();
        System.out.println("获取连接池");
                //通过构造方法将connection类传入包装类中
        ConnectionWrapper cw = new ConnectionWrapper(conn,list);
                //返回包装类
        return cw;
        
    }
}

3.利用装饰者模式,创建Connection的包装类ConnectionWrapper

装饰者模式的具体介绍参照装饰者模式

装饰者模式中,装饰者和被装饰者需要继承同一个类或者实现同一个接口。由于Connection本身就是一个接口,所以很自然的让装饰者继承这个接口。

通过查看Connection接口的api发现,接口中的抽象方法实在是太多了。如果我们直接让装饰者类继承,需要重写太多方法。

以下为部分方法:

所以在这里,我们需要使用适配器模式,新增加一个类ConnectionAdapter,让它来实现Connection接口,让装饰者类继承ConnectionAdapter类,这样就可以只重写需要用的方法啦。

该类部分截图:

装饰者类:

public class ConnectionWrapper extends ConnectionAdapter {

    private Connection conn;
    private LinkedList<Connection> list;
    public ConnectionWrapper() {
        
    }
  //通过构造方法将被装饰者类传入进来并赋值给内部类。将List集合也传进来,因为有归还连接的操作。
public ConnectionWrapper(Connection conn,LinkedList<Connection> list) { this.conn = conn; this.list = list; } @Override
  //重写close方法,归还连接。
public void close() throws SQLException { System.out.println("前"+list.size()); list.addLast(this); System.out.println("后"+list.size()); }
//以下两个方法就调用以前的方法就行 @Override
public Statement createStatement() throws SQLException { // TODO Auto-generated method stub return conn.createStatement(); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { // TODO Auto-generated method stub return conn.prepareStatement(sql); }

测试类:

public class Test {

    public static void main(String[] args) throws SQLException {
        Connection conn = MyDataSource.getConnection();
                //注意:这里的conn已经不是单纯的Connection了,它是实际传过来的装饰类ConnectionWrapper
        String sql = "select * from student";
        PreparedStatement st  = conn.prepareStatement(sql);
        ResultSet rs = st.executeQuery();
        while(rs.next()){
            System.out.println(
                    rs.getString("id")+"  "+rs.getString("name")
                    +"   "+rs.getString("score"));
        }
               //这里调用的也不是Connection以前的close()方法了,这里是包装类的增强close()方法。不销毁连接,只归还连接。
        conn.close();
    }
}

运行结果如下:

以上,就是一个简易的jdbc连接池。

然而现实有两个比较常用的,封装好的连接池,他们分别是DBCP和C3P0,以下介绍他们的用法:

一.DBCP连接池

apache组织出品。

 1.导入jar包(commons-dbcp-1.4.jar和commons-pool-1.5.6.jar)

(emmmm请无视中间的dbutils的jar包......)

2.使用

  a.硬编码(不推荐使用)

  以下是硬编码方式的配置信息:

     //创建连接池
        BasicDataSource ds = new BasicDataSource();
        
        //配置信息
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql:///exercise");
        ds.setUsername("root");
        ds.setPassword("123456");

  b.采用配置文件的方式读取配置信息。这里拿properties文件举例。(名称为dbcp.properties)

代码如下:

  //存放配置文件
    Properties prop = new Properties();
    prop.load(new FileInputStrea("src/dbcp.properties"))            
    //创建连接池
    DataSource ds = new BasicDataSourceFactory().createDataSource(prop);   
   Connection conn=ds.getConnection();

二.C3P0连接池(比较常见)

hibernate和spring使用,有自动回收空闲连接的功能。

1.导入jar包(c3p0-0.9.1.2.jar)

2.使用

  a.硬编码:

ComboPooledDataSource ds = new ComboPooledDataSource();
        
        //设置基本参数
        ds.setDriverClass("com.mysql.jdbc.Driver");
        ds.setJdbcUrl("jdbc:mysql:///exercise");
        ds.setUser("root");
        ds.setPassword("123456");
        
        Connection conn=ds.getConnection();

  b.读取配置文件

  注意:配置文件的名称:c3p0.properties 或者 c3p0-config.xml时,可以直接使用new ComboPooledDataSource()来获取配置文件(默认配置)。

      new ComboPooledDataSource(String configName)//使用命名的配置 若配置的名字找不到,使用默认的配置

  以下用properties文件举例:

  代码如下:

   //由于配置文件写的默认名字,这里使用无参构造
    ComboPooledDataSource ds =new ComboPooledDataSource();
    Connection conn=ds.getConnection();
原文地址:https://www.cnblogs.com/tonbby/p/9043347.html