一個效果很是不錯的JAVA數據庫鏈接池

package studytest;java

//
//    一個效果很是不錯的JAVA數據庫鏈接池.
//    from:http://www.jxer.com/home/?uid-195-action-viewspace-itemid-332
//    雖然如今用APACHE COMMONS DBCP能夠很是方便的創建數據庫鏈接池,
//    可是像這篇文章把數據庫鏈接池的內部原理寫的這麼透徹,注視這麼完整,
//    真是很是可貴,讓開發人員能夠更深層次的理解數據庫鏈接池,真是很是感
//    謝這篇文章的做者。
//
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Enumeration;
import java.util.Vector;sql

public class ConnectionPool {數據庫

    private String jdbcDriver = ""; // 數據庫驅動
    private String dbUrl = ""; // 數據 URL
    private String dbUsername = ""; // 數據庫用戶名
    private String dbPassword = ""; // 數據庫用戶密碼
    private String testTable = ""; // 測試鏈接是否可用的測試表名,默認沒有測試表
    private int initialConnections = 10; // 鏈接池的初始大小
    private int incrementalConnections = 5; // 鏈接池自動增長的大小
    private int maxConnections = 50; // 鏈接池最大的大小
    private Vector connections = null; // 存放鏈接池中數據庫鏈接的向量 , 初始時爲 null
// 它中存放的對象爲 PooledConnection 型oracle

   
    public ConnectionPool(String jdbcDriver, String dbUrl, String dbUsername,
                          String dbPassword) {函數

        this.jdbcDriver = jdbcDriver;
        this.dbUrl = dbUrl;
        this.dbUsername = dbUsername;
        this.dbPassword = dbPassword;
    }測試

   
    public int getInitialConnections() {
        return this.initialConnections;
    }ui

   
    public void setInitialConnections(int initialConnections) {
        this.initialConnections = initialConnections;
    }this

   
    public int getIncrementalConnections() {
        return this.incrementalConnections;
    }spa

   
    public void setIncrementalConnections(int incrementalConnections) {
        this.incrementalConnections = incrementalConnections;
    }orm

   
    public int getMaxConnections() {
        return this.maxConnections;
    }

   
    public void setMaxConnections(int maxConnections) {
        this.maxConnections = maxConnections;
    }

   
    public String getTestTable() {
        return this.testTable;
    }

   
    public void setTestTable(String testTable) {
        this.testTable = testTable;
    }

   
    public synchronized void createPool() throws Exception {
        // 確保鏈接池沒有建立
        // 假如鏈接池己經建立了,保存鏈接的向量 connections 不會爲空
        if (connections != null) {
            return; // 假如己經建立,則返回
        }
        // 實例化 JDBC Driver 中指定的驅動類實例
        Driver driver = (Driver) (Class.forName(this.jdbcDriver).newInstance());
        DriverManager.registerDriver(driver); // 註冊 JDBC 驅動程序
        // 建立保存鏈接的向量 , 初始時有 0 個元素
        connections = new Vector();
        // 根據 initialConnections 中設置的值,建立鏈接。
        createConnections(this.initialConnections);
        System.out.println(" 數據庫鏈接池建立成功! ");
    }

   
    private void createConnections(int numConnections) throws SQLException {
        // 循環建立指定數目的數據庫鏈接
        for (int x = 0; x < numConnections; x++) {
            // 是否鏈接池中的數據庫鏈接的數量己經達到最大?最大值由類成員 maxConnections
            // 指出,假如 maxConnections 爲 0 或負數,表示鏈接數量沒有限制。
            // 假如鏈接數己經達到最大,即退出。
            if (this.maxConnections > 0 &&
                this.connections.size() >= this.maxConnections) {
                break;
            }
            //add a new PooledConnection object to connections vector
            // 增長一個鏈接到鏈接池中(向量 connections 中)
            try {
                connections.addElement(new PooledConnection(newConnection()));
            } catch (SQLException e) {
                System.out.println(" 建立數據庫鏈接失敗! " + e.getMessage());
                throw new SQLException();
            }
            System.out.println(" 數據庫鏈接己建立 ......");
        }
    }

   
    private Connection newConnection() throws SQLException {
        // 建立一個數據庫鏈接
        Connection conn = DriverManager.getConnection(dbUrl, dbUsername,
                dbPassword);
        // 假如這是第一次建立數據庫鏈接,即檢查數據庫,得到此數據庫答應支持的
        // 最大客戶鏈接數目
        //connections.size()==0 表示目前沒有鏈接己被建立
        if (connections.size() == 0) {
            DatabaseMetaData metaData = conn.getMetaData();
            int driverMaxConnections = metaData.getMaxConnections();
            // 數據庫返回的 driverMaxConnections 若爲 0 ,表示此數據庫沒有最大
            // 鏈接限制,或數據庫的最大鏈接限制不知道
            //driverMaxConnections 爲返回的一個整數,表示此數據庫答應客戶鏈接的數目
            // 假如鏈接池中設置的最大鏈接數量大於數據庫答應的鏈接數目 , 則置鏈接池的最大
            // 鏈接數目爲數據庫答應的最大數目
            if (driverMaxConnections > 0 &&
                this.maxConnections > driverMaxConnections) {
                this.maxConnections = driverMaxConnections;
            }
        }
        return conn; // 返回建立的新的數據庫鏈接
    }

   

    public synchronized Connection getConnection() throws SQLException {
        // 確保鏈接池己被建立
        if (connections == null) {
            return null; // 鏈接池還沒建立,則返回 null
        }
        Connection conn = getFreeConnection(); // 得到一個可用的數據庫鏈接
        // 假如目前沒有能夠使用的鏈接,即全部的鏈接都在使用中
        while (conn == null) {
            // 等一會再試
            wait(250);
            conn = getFreeConnection(); // 從新再試,直到得到可用的鏈接,假如
            //getFreeConnection() 返回的爲 null
            // 則代表建立一批鏈接後也不可得到可用鏈接
        }
        return conn; // 返回得到的可用的鏈接
    }

   
    private Connection getFreeConnection() throws SQLException {
        // 從鏈接池中得到一個可用的數據庫鏈接
        Connection conn = findFreeConnection();
        if (conn == null) {
            // 假如目前鏈接池中沒有可用的鏈接
            // 建立一些鏈接
            createConnections(incrementalConnections);
            // 從新從池中查找是否有可用鏈接
            conn = findFreeConnection();
            if (conn == null) {
                // 假如建立鏈接後仍得到不到可用的鏈接,則返回 null
                return null;
            }
        }
        return conn;
    }

   
    private Connection findFreeConnection() throws SQLException {
        Connection conn = null;
        PooledConnection pConn = null;
        // 得到鏈接池向量中全部的對象
        Enumeration enumerate = connections.elements();
        // 遍歷全部的對象,看是否有可用的鏈接
        while (enumerate.hasMoreElements()) {
            pConn = (PooledConnection) enumerate.nextElement();
            if (!pConn.isBusy()) {
                // 假如此對象不忙,則得到它的數據庫鏈接並把它設爲忙
                conn = pConn.getConnection();
                pConn.setBusy(true);
                // 測試此鏈接是否可用
                if (!testConnection(conn)) {
                    // 假如此鏈接不可再用了,則建立一個新的鏈接,
                    // 並替換此不可用的鏈接對象,假如建立失敗,返回 null
                    try {
                        conn = newConnection();
                    } catch (SQLException e) {
                        System.out.println(" 建立數據庫鏈接失敗! " + e.getMessage());
                        return null;
                    }
                    pConn.setConnection(conn);
                }
                break; // 己經找到一個可用的鏈接,退出
            }
        }
        return conn; // 返回找到到的可用鏈接
    }

   
    private boolean testConnection(Connection conn) {
        try {
            // 斷定測試表是否存在
            if (testTable.equals("")) {
                // 假如測試表爲空,試着使用此鏈接的 setAutoCommit() 方法
                // 來斷定鏈接否可用(此方法只在部分數據庫可用,假如不可用 ,
                // 拋出異常)。注重:使用測試表的方法更可靠
                conn.setAutoCommit(true);
            } else { // 有測試表的時候使用測試表測試
                //check if this connection is valid
                Statement stmt = conn.createStatement();
                stmt.execute("select count(*) from " + testTable);
            }
        } catch (SQLException e) {
            // 上面拋出異常,此鏈接己不可用,關閉它,並返回 false;
            closeConnection(conn);
            return false;
        }
        // 鏈接可用,返回 true
        return true;
    }

   
    public void returnConnection(Connection conn) {
        // 確保鏈接池存在,假如鏈接沒有建立(不存在),直接返回
        if (connections == null) {
            System.out.println(" 鏈接池不存在,沒法返回此鏈接到鏈接池中 !");
            return;
        }
        PooledConnection pConn = null;
        Enumeration enumerate = connections.elements();
        // 遍歷鏈接池中的全部鏈接,找到這個要返回的鏈接對象
        while (enumerate.hasMoreElements()) {
            pConn = (PooledConnection) enumerate.nextElement();
            // 先找到鏈接池中的要返回的鏈接對象
            if (conn == pConn.getConnection()) {
                // 找到了 , 設置此鏈接爲空閒狀態
                pConn.setBusy(false);
                break;
            }
        }
    }

   

    public synchronized void refreshConnections() throws SQLException {
        // 確保鏈接池己創新存在
        if (connections == null) {
            System.out.println(" 鏈接池不存在,沒法刷新 !");
            return;
        }
        PooledConnection pConn = null;
        Enumeration enumerate = connections.elements();
        while (enumerate.hasMoreElements()) {
            // 得到一個鏈接對象
            pConn = (PooledConnection) enumerate.nextElement();
            // 假如對象忙則等 5 秒 ,5 秒後直接刷新
            if (pConn.isBusy()) {
                wait(5000); // 等 5 秒
            }
            // 關閉此鏈接,用一個新的鏈接代替它。
            closeConnection(pConn.getConnection());
            pConn.setConnection(newConnection());
            pConn.setBusy(false);
        }
    }

   
    public synchronized void closeConnectionPool() throws SQLException {
        // 確保鏈接池存在,假如不存在,返回
        if (connections == null) {
            System.out.println(" 鏈接池不存在,沒法關閉 !");
            return;
        }
        PooledConnection pConn = null;
        Enumeration enumerate = connections.elements();
        while (enumerate.hasMoreElements()) {
            pConn = (PooledConnection) enumerate.nextElement();
            // 假如忙,等 5 秒
            if (pConn.isBusy()) {
                wait(5000); // 等 5 秒
            }
            //5 秒後直接關閉它
            closeConnection(pConn.getConnection());
            // 從鏈接池向量中刪除它
            connections.removeElement(pConn);
        }
        // 置鏈接池爲空
        connections = null;
    }

   
    private void closeConnection(Connection conn) {
        try {
            conn.close();
        } catch (SQLException e) {
            System.out.println(" 關閉數據庫鏈接出錯: " + e.getMessage());
        }
    }

   
    private void wait(int mSeconds) {
        try {
            Thread.sleep(mSeconds);
        } catch (InterruptedException e) {
        }
    }

   

    class PooledConnection {
        Connection connection = null; // 數據庫鏈接
        boolean busy = false; // 此鏈接是否正在使用的標誌,默認沒有正在使用
        // 構造函數,根據一個 Connection 構告一個 PooledConnection 對象
        public PooledConnection(Connection connection) {
            this.connection = connection;
        }

        // 返回此對象中的鏈接
        public Connection getConnection() {
            return connection;
        }

        // 設置此對象的,鏈接
        public void setConnection(Connection connection) {
            this.connection = connection;
        }

        // 得到對象鏈接是否忙
        public boolean isBusy() {
            return busy;
        }

        // 設置對象的鏈接正在忙
        public void setBusy(boolean busy) {
            this.busy = busy;
        }
    }


    public static void main(String[] args) {
       
        ConnectionPool connPool
                = new ConnectionPool("oracle.jdbc.driver.OracleDriver",
                                     "jdbc:oracle:thin:@*.*.*.*"
                                     , "name", "password");

        try {
            connPool.createPool();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        try {
            Connection conn = connPool.getConnection();
        } catch (SQLException ex1) {
            ex1.printStackTrace();
        }

    }

}

相關文章
相關標籤/搜索