自定義一個簡單連接池以及常見連接池的使用


由於使用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();

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM