<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Terry.Li-彬

    虛其心,可解天下之問;專其心,可治天下之學;靜其心,可悟天下之理;恒其心,可成天下之業。

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      143 隨筆 :: 344 文章 :: 130 評論 :: 0 Trackbacks

    一個經試用效果非常不錯的數據庫連接池

    前言:

    雖說現在許多企業級的應用服務器均自己帶有數據庫連接池功能,就連 Tomcat 也支持了這種功能。然而在許多時候,我們還是要使用數據庫連接池,如:訪問數據庫的 Java 桌面應用程序等。這個數據庫連接池是我根據《 Inside Servlets 》一書中的示例改寫而成,經過試用,效果非常不錯。特發布共享。 ( 作者: abnerchai 聯系我: mailto:josserchai@yahoo.com)

    源代碼

    //ConnectionPool.java

    package com.abner.dbconnector;

    import java.sql.*;

    import java.util.*;

    /**

    * ConnectionPool 類創建了一個對特定數據庫指定大小的連接池。連接池對象

    * 允許客戶端指定 JDBC 驅動程序,數據庫,使用數據庫的用戶名和密碼。而且,

    * 客戶端能指定連接池的在初始創建是產生數據庫連接的數量,和指定當連接

    * 不夠時每次自動增加連接的數量及連接池最多的數據庫連接的數量。

    *

    * 對外提供的方法有: ConnectionPool :構造函數

    * getInitialConnections: 返回連接池初始化大小

    * setInitialConnections: 設置連接池初始化大小

    * getIncrementalConnections: 返回連接池自動增加的增量

    * setIncrementalConnections: 設置連接池自動增加的大小

    * getMaxConnections :獲得連接池的最大可允許的連接數

    * setMaxConnections :設置連接池的最大可允許的連接數

    * getTestTable :獲得測試表的名字

    * setTestTable :設置測試表的名字

    * createPool: 創建連接池 , 線程己同步

    * getConnection: 從連接池中獲得一個數據庫連接

    * returnConnection: 返回一個連接到連接池中

    * refreshConnections: 刷新連接池

    * closeConnectionPool: 關閉連接池

    *

    *

    * @author abnerchai Email: josserchai@yahoo.com

    * @version 1.0.0

    *

    */

    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 型

    /**

    * 構造函數

    *

    * @param jdbcDriver String JDBC 驅動類串

    * @param dbUrl String 數據庫 URL

    * @param dbUsername String 連接數據庫用戶名

    * @param dbPassword String 連接數據庫用戶的密碼

    *

    */

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

    this.jdbcDriver = jdbcDriver;

    this.dbUrl = dbUrl;

    this.dbUsername = dbUsername;

    this.dbPassword = dbPassword;

    }

    /**

    * 返回連接池的初始大小

    *

    * @return 初始連接池中可獲得的連接數量

    */

    public int getInitialConnections() {

    return this.initialConnections;

    }

    /**

    * 設置連接池的初始大小

    *

    * @param 用于設置初始連接池中連接的數量

    */

    public void setInitialConnections(int initialConnections) {

    this.initialConnections = initialConnections;

    }

    /**

    * 返回連接池自動增加的大小 、

    *

    * @return 連接池自動增加的大小

    */

    public int getIncrementalConnections() {

    return this.incrementalConnections;

    }

    /**

    * 設置連接池自動增加的大小

    * @param 連接池自動增加的大小

    */

    public void setIncrementalConnections(int incrementalConnections) {

    this.incrementalConnections = incrementalConnections;

    }

    /**

    * 返回連接池中最大的可用連接數量

    * @return 連接池中最大的可用連接數量

    */

    public int getMaxConnections() {

    return this.maxConnections;

    }

    /**

    * 設置連接池中最大可用的連接數量

    *

    * @param 設置連接池中最大可用的連接數量值

    */

    public void setMaxConnections(int maxConnections) {

    this.maxConnections = maxConnections;

    }

    /**

    * 獲取測試數據庫表的名字

    *

    * @return 測試數據庫表的名字

    */

    public String getTestTable() {

    return this.testTable;

    }

    /**

    * 設置測試表的名字

    * @param testTable String 測試表的名字

    */

    public void setTestTable(String testTable) {

    this.testTable = testTable;

    }

    /**

    *

    * 創建一個數據庫連接池,連接池中的可用連接的數量采用類成員

    * initialConnections 中設置的值

    */

    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(" 數據庫連接池創建成功! ");

    }

    /**

    * 創建由 numConnections 指定數目的數據庫連接 , 并把這些連接

    * 放入 connections 向量中

    *

    * @param numConnections 要創建的數據庫連接的數目

    */

    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(" 數據庫連接己創建 ......");

    }

    }

    /**

    * 創建一個新的數據庫連接并返回它

    *

    * @return 返回一個新創建的數據庫連接

    */

    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; // 返回創建的新的數據庫連接

    }

    /**

    * 通過調用 getFreeConnection() 函數返回一個可用的數據庫連接 ,

    * 如果當前沒有可用的數據庫連接,并且更多的數據庫連接不能創

    * 建(如連接池大小的限制),此函數等待一會再嘗試獲取。

    *

    * @return 返回一個可用的數據庫連接對象

    */

    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;// 返回獲得的可用的連接

    }

    /**

    * 本函數從連接池向量 connections 中返回一個可用的的數據庫連接,如果

    * 當前沒有可用的數據庫連接,本函數則根據 incrementalConnections 設置

    * 的值創建幾個數據庫連接,并放入連接池中。

    * 如果創建后,所有的連接仍都在使用中,則返回 null

    * @return 返回一個可用的數據庫連接

    */

    private Connection getFreeConnection() throws SQLException {

    // 從連接池中獲得一個可用的數據庫連接

    Connection conn = findFreeConnection();

    if (conn == null) {

    // 如果目前連接池中沒有可用的連接

    // 創建一些連接

    createConnections(incrementalConnections);

    // 重新從池中查找是否有可用連接

    conn = findFreeConnection();

    if (conn == null) {

    // 如果創建連接后仍獲得不到可用的連接,則返回 null

    return null;

    }

    }

    return conn;

    }

    /**

    * 查找連接池中所有的連接,查找一個可用的數據庫連接,

    * 如果沒有可用的連接,返回 null

    *

    * @return 返回一個可用的數據庫連接

    */

    private Connection findFreeConnection() throws SQLException {

    Connection conn = null;

    PooledConnection pConn = null;

    // 獲得連接池向量中所有的對象

    Enumeration enum = connections.elements();

    // 遍歷所有的對象,看是否有可用的連接

    while (enum.hasMoreElements()) {

    pConn = (PooledConnection) enum.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;// 返回找到到的可用連接

    }

    /**

    * 測試一個連接是否可用,如果不可用,關掉它并返回 false

    * 否則可用返回 true

    *

    * @param conn 需要測試的數據庫連接

    * @return 返回 true 表示此連接可用, false 表示不可用

    */

    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;

    }

    /**

    * 此函數返回一個數據庫連接到連接池中,并把此連接置為空閑。

    * 所有使用連接池獲得的數據庫連接均應在不使用此連接時返回它。

    *

    * @param 需返回到連接池中的連接對象

    */

    public void returnConnection(Connection conn) {

    // 確保連接池存在,如果連接沒有創建(不存在),直接返回

    if (connections == null) {

    System.out.println(" 連接池不存在,無法返回此連接到連接池中 !");

    return;

    }

    PooledConnection pConn = null;

    Enumeration enum = connections.elements();

    // 遍歷連接池中的所有連接,找到這個要返回的連接對象

    while (enum.hasMoreElements()) {

    pConn = (PooledConnection) enum.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 enum = connections.elements();

    while (enum.hasMoreElements()) {

    // 獲得一個連接對象

    pConn = (PooledConnection) enum.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 enum = connections.elements();

    while (enum.hasMoreElements()) {

    pConn = (PooledConnection) enum.nextElement();

    // 如果忙,等 5 秒

    if (pConn.isBusy()) {

    wait(5000); // 等 5 秒

    }

    //5 秒后直接關閉它

    closeConnection(pConn.getConnection());

    // 從連接池向量中刪除它

    connections.removeElement(pConn);

    }

    // 置連接池為空

    connections = null;

    }

    /**

    * 關閉一個數據庫連接

    *

    * @param 需要關閉的數據庫連接

    */

    private void closeConnection(Connection conn) {

    try {

    conn.close();

    }catch (SQLException e) {

    System.out.println(" 關閉數據庫連接出錯: "+e.getMessage());

    }

    }

    /**

    * 使程序等待給定的毫秒數

    *

    * @param 給定的毫秒數

    */

    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;

    }

    }

    }

    這個程序所有的解釋我都詳細地寫在了源程序中,我想就不必多解說了吧。

    posted on 2007-09-06 18:15 禮物 閱讀(264) 評論(0)  編輯  收藏 所屬分類: java
    主站蜘蛛池模板: 日产久久强奸免费的看| 久久久久亚洲av成人无码电影 | 亚洲av日韩av天堂影片精品| 久久国产精品成人片免费| 久久夜色精品国产噜噜噜亚洲AV| 人人爽人人爽人人片av免费 | 亚洲区小说区图片区| XXX2高清在线观看免费视频| 久久精品国产精品亚洲毛片| 国产jizzjizz免费看jizz| 免费毛片在线看不用播放器| 亚洲一线产品二线产品| 亚洲无av在线中文字幕| 丁香花免费完整高清观看| 国产福利免费视频| 亚洲一区二区三区丝袜| 亚洲老妈激情一区二区三区| 女人18一级毛片免费观看| 中国国产高清免费av片| 亚洲中文字幕久久精品无码A | 无码中文字幕av免费放| 国产成人精品亚洲| 亚洲性天天干天天摸| 四虎永久免费观看| 男女超爽刺激视频免费播放| 国产免费伦精品一区二区三区| 亚洲人AV永久一区二区三区久久| 国产区图片区小说区亚洲区| 精品亚洲麻豆1区2区3区| 亚洲Av无码国产情品久久 | 国产精品亚洲综合网站| 精品亚洲麻豆1区2区3区| 国产成人免费全部网站| 国产成人精品免费视频动漫| 99久久免费国产精精品| 真人无码作爱免费视频| 亚洲熟妇成人精品一区| 亚洲福利视频网址| 亚洲AV成人无码久久精品老人| 91精品免费久久久久久久久| h视频免费高清在线观看|