Terry.Li-彬

          虛其心,可解天下之問;專其心,可治天下之學(xué);靜其心,可悟天下之理;恒其心,可成天下之業(yè)。

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            143 隨筆 :: 344 文章 :: 130 評(píng)論 :: 0 Trackbacks

          一個(gè)經(jīng)試用效果非常不錯(cuò)的數(shù)據(jù)庫連接池

          前言:

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

          源代碼

          //ConnectionPool.java

          package com.abner.dbconnector;

          import java.sql.*;

          import java.util.*;

          /**

          * ConnectionPool 類創(chuàng)建了一個(gè)對(duì)特定數(shù)據(jù)庫指定大小的連接池。連接池對(duì)象

          * 允許客戶端指定 JDBC 驅(qū)動(dòng)程序,數(shù)據(jù)庫,使用數(shù)據(jù)庫的用戶名和密碼。而且,

          * 客戶端能指定連接池的在初始創(chuàng)建是產(chǎn)生數(shù)據(jù)庫連接的數(shù)量,和指定當(dāng)連接

          * 不夠時(shí)每次自動(dòng)增加連接的數(shù)量及連接池最多的數(shù)據(jù)庫連接的數(shù)量。

          *

          * 對(duì)外提供的方法有: ConnectionPool :構(gòu)造函數(shù)

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

          * setInitialConnections: 設(shè)置連接池初始化大小

          * getIncrementalConnections: 返回連接池自動(dòng)增加的增量

          * setIncrementalConnections: 設(shè)置連接池自動(dòng)增加的大小

          * getMaxConnections :獲得連接池的最大可允許的連接數(shù)

          * setMaxConnections :設(shè)置連接池的最大可允許的連接數(shù)

          * getTestTable :獲得測(cè)試表的名字

          * setTestTable :設(shè)置測(cè)試表的名字

          * createPool: 創(chuàng)建連接池 , 線程己同步

          * getConnection: 從連接池中獲得一個(gè)數(shù)據(jù)庫連接

          * returnConnection: 返回一個(gè)連接到連接池中

          * refreshConnections: 刷新連接池

          * closeConnectionPool: 關(guān)閉連接池

          *

          *

          * @author abnerchai Email: josserchai@yahoo.com

          * @version 1.0.0

          *

          */

          public class ConnectionPool {

          private String jdbcDriver = ""; // 數(shù)據(jù)庫驅(qū)動(dòng)

          private String dbUrl = ""; // 數(shù)據(jù) URL

          private String dbUsername = ""; // 數(shù)據(jù)庫用戶名

          private String dbPassword = ""; // 數(shù)據(jù)庫用戶密碼

          private String testTable = ""; // 測(cè)試連接是否可用的測(cè)試表名,默認(rèn)沒有測(cè)試表

          private int initialConnections = 10; // 連接池的初始大小

          private int incrementalConnections = 5;// 連接池自動(dòng)增加的大小

          private int maxConnections = 50; // 連接池最大的大小

          private Vector connections = null; // 存放連接池中數(shù)據(jù)庫連接的向量 , 初始時(shí)為 null

          // 它中存放的對(duì)象為 PooledConnection 型

          /**

          * 構(gòu)造函數(shù)

          *

          * @param jdbcDriver String JDBC 驅(qū)動(dòng)類串

          * @param dbUrl String 數(shù)據(jù)庫 URL

          * @param dbUsername String 連接數(shù)據(jù)庫用戶名

          * @param dbPassword String 連接數(shù)據(jù)庫用戶的密碼

          *

          */

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

          this.jdbcDriver = jdbcDriver;

          this.dbUrl = dbUrl;

          this.dbUsername = dbUsername;

          this.dbPassword = dbPassword;

          }

          /**

          * 返回連接池的初始大小

          *

          * @return 初始連接池中可獲得的連接數(shù)量

          */

          public int getInitialConnections() {

          return this.initialConnections;

          }

          /**

          * 設(shè)置連接池的初始大小

          *

          * @param 用于設(shè)置初始連接池中連接的數(shù)量

          */

          public void setInitialConnections(int initialConnections) {

          this.initialConnections = initialConnections;

          }

          /**

          * 返回連接池自動(dòng)增加的大小 、

          *

          * @return 連接池自動(dòng)增加的大小

          */

          public int getIncrementalConnections() {

          return this.incrementalConnections;

          }

          /**

          * 設(shè)置連接池自動(dòng)增加的大小

          * @param 連接池自動(dòng)增加的大小

          */

          public void setIncrementalConnections(int incrementalConnections) {

          this.incrementalConnections = incrementalConnections;

          }

          /**

          * 返回連接池中最大的可用連接數(shù)量

          * @return 連接池中最大的可用連接數(shù)量

          */

          public int getMaxConnections() {

          return this.maxConnections;

          }

          /**

          * 設(shè)置連接池中最大可用的連接數(shù)量

          *

          * @param 設(shè)置連接池中最大可用的連接數(shù)量值

          */

          public void setMaxConnections(int maxConnections) {

          this.maxConnections = maxConnections;

          }

          /**

          * 獲取測(cè)試數(shù)據(jù)庫表的名字

          *

          * @return 測(cè)試數(shù)據(jù)庫表的名字

          */

          public String getTestTable() {

          return this.testTable;

          }

          /**

          * 設(shè)置測(cè)試表的名字

          * @param testTable String 測(cè)試表的名字

          */

          public void setTestTable(String testTable) {

          this.testTable = testTable;

          }

          /**

          *

          * 創(chuàng)建一個(gè)數(shù)據(jù)庫連接池,連接池中的可用連接的數(shù)量采用類成員

          * initialConnections 中設(shè)置的值

          */

          public synchronized void createPool() throws Exception {

          // 確保連接池沒有創(chuàng)建

          // 如果連接池己經(jīng)創(chuàng)建了,保存連接的向量 connections 不會(huì)為空

          if (connections != null) {

          return; // 如果己經(jīng)創(chuàng)建,則返回

          }

          // 實(shí)例化 JDBC Driver 中指定的驅(qū)動(dòng)類實(shí)例

          Driver driver = (Driver) (Class.forName(this.jdbcDriver).newInstance());

          DriverManager.registerDriver(driver); // 注冊(cè) JDBC 驅(qū)動(dòng)程序

          // 創(chuàng)建保存連接的向量 , 初始時(shí)有 0 個(gè)元素

          connections = new Vector();

          // 根據(jù) initialConnections 中設(shè)置的值,創(chuàng)建連接。

          createConnections(this.initialConnections);

          System.out.println(" 數(shù)據(jù)庫連接池創(chuàng)建成功! ");

          }

          /**

          * 創(chuàng)建由 numConnections 指定數(shù)目的數(shù)據(jù)庫連接 , 并把這些連接

          * 放入 connections 向量中

          *

          * @param numConnections 要?jiǎng)?chuàng)建的數(shù)據(jù)庫連接的數(shù)目

          */

          private void createConnections(int numConnections) throws SQLException {

          // 循環(huán)創(chuàng)建指定數(shù)目的數(shù)據(jù)庫連接

          for (int x = 0; x < numConnections; x++) {

          // 是否連接池中的數(shù)據(jù)庫連接的數(shù)量己經(jīng)達(dá)到最大?最大值由類成員 maxConnections

          // 指出,如果 maxConnections 為 0 或負(fù)數(shù),表示連接數(shù)量沒有限制。

          // 如果連接數(shù)己經(jīng)達(dá)到最大,即退出。

          if (this.maxConnections > 0 && this.connections.size() >= this.maxConnections) {

          break;

          }

          //add a new PooledConnection object to connections vector

          // 增加一個(gè)連接到連接池中(向量 connections 中)

          try{

          connections.addElement(new PooledConnection(newConnection()));

          }catch(SQLException e){

          System.out.println(" 創(chuàng)建數(shù)據(jù)庫連接失??! "+e.getMessage());

          throw new SQLException();

          }

          System.out.println(" 數(shù)據(jù)庫連接己創(chuàng)建 ......");

          }

          }

          /**

          * 創(chuàng)建一個(gè)新的數(shù)據(jù)庫連接并返回它

          *

          * @return 返回一個(gè)新創(chuàng)建的數(shù)據(jù)庫連接

          */

          private Connection newConnection() throws SQLException {

          // 創(chuàng)建一個(gè)數(shù)據(jù)庫連接

          Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);

          // 如果這是第一次創(chuàng)建數(shù)據(jù)庫連接,即檢查數(shù)據(jù)庫,獲得此數(shù)據(jù)庫允許支持的

          // 最大客戶連接數(shù)目

          //connections.size()==0 表示目前沒有連接己被創(chuàng)建

          if (connections.size() == 0) {

          DatabaseMetaData metaData = conn.getMetaData();

          int driverMaxConnections = metaData.getMaxConnections();

          // 數(shù)據(jù)庫返回的 driverMaxConnections 若為 0 ,表示此數(shù)據(jù)庫沒有最大

          // 連接限制,或數(shù)據(jù)庫的最大連接限制不知道

          //driverMaxConnections 為返回的一個(gè)整數(shù),表示此數(shù)據(jù)庫允許客戶連接的數(shù)目

          // 如果連接池中設(shè)置的最大連接數(shù)量大于數(shù)據(jù)庫允許的連接數(shù)目 , 則置連接池的最大

          // 連接數(shù)目為數(shù)據(jù)庫允許的最大數(shù)目

          if (driverMaxConnections > 0 && this.maxConnections > driverMaxConnections) {

          this.maxConnections = driverMaxConnections;

          }

          }

          return conn; // 返回創(chuàng)建的新的數(shù)據(jù)庫連接

          }

          /**

          * 通過調(diào)用 getFreeConnection() 函數(shù)返回一個(gè)可用的數(shù)據(jù)庫連接 ,

          * 如果當(dāng)前沒有可用的數(shù)據(jù)庫連接,并且更多的數(shù)據(jù)庫連接不能創(chuàng)

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

          *

          * @return 返回一個(gè)可用的數(shù)據(jù)庫連接對(duì)象

          */

          public synchronized Connection getConnection() throws SQLException {

          // 確保連接池己被創(chuàng)建

          if (connections == null) {

          return null; // 連接池還沒創(chuàng)建,則返回 null

          }

          Connection conn = getFreeConnection(); // 獲得一個(gè)可用的數(shù)據(jù)庫連接

          // 如果目前沒有可以使用的連接,即所有的連接都在使用中

          while (conn == null){

          // 等一會(huì)再試

          wait(250);

          conn = getFreeConnection(); // 重新再試,直到獲得可用的連接,如果

          //getFreeConnection() 返回的為 null

          // 則表明創(chuàng)建一批連接后也不可獲得可用連接

          }

          return conn;// 返回獲得的可用的連接

          }

          /**

          * 本函數(shù)從連接池向量 connections 中返回一個(gè)可用的的數(shù)據(jù)庫連接,如果

          * 當(dāng)前沒有可用的數(shù)據(jù)庫連接,本函數(shù)則根據(jù) incrementalConnections 設(shè)置

          * 的值創(chuàng)建幾個(gè)數(shù)據(jù)庫連接,并放入連接池中。

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

          * @return 返回一個(gè)可用的數(shù)據(jù)庫連接

          */

          private Connection getFreeConnection() throws SQLException {

          // 從連接池中獲得一個(gè)可用的數(shù)據(jù)庫連接

          Connection conn = findFreeConnection();

          if (conn == null) {

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

          // 創(chuàng)建一些連接

          createConnections(incrementalConnections);

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

          conn = findFreeConnection();

          if (conn == null) {

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

          return null;

          }

          }

          return conn;

          }

          /**

          * 查找連接池中所有的連接,查找一個(gè)可用的數(shù)據(jù)庫連接,

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

          *

          * @return 返回一個(gè)可用的數(shù)據(jù)庫連接

          */

          private Connection findFreeConnection() throws SQLException {

          Connection conn = null;

          PooledConnection pConn = null;

          // 獲得連接池向量中所有的對(duì)象

          Enumeration enum = connections.elements();

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

          while (enum.hasMoreElements()) {

          pConn = (PooledConnection) enum.nextElement();

          if (!pConn.isBusy()) {

          // 如果此對(duì)象不忙,則獲得它的數(shù)據(jù)庫連接并把它設(shè)為忙

          conn = pConn.getConnection();

          pConn.setBusy(true);

          // 測(cè)試此連接是否可用

          if (!testConnection(conn)) {

          // 如果此連接不可再用了,則創(chuàng)建一個(gè)新的連接,

          // 并替換此不可用的連接對(duì)象,如果創(chuàng)建失敗,返回 null

          try{

          conn = newConnection();

          }catch(SQLException e){

          System.out.println(" 創(chuàng)建數(shù)據(jù)庫連接失??! "+e.getMessage());

          return null;

          }

          pConn.setConnection(conn);

          }

          break; // 己經(jīng)找到一個(gè)可用的連接,退出

          }

          }

          return conn;// 返回找到到的可用連接

          }

          /**

          * 測(cè)試一個(gè)連接是否可用,如果不可用,關(guān)掉它并返回 false

          * 否則可用返回 true

          *

          * @param conn 需要測(cè)試的數(shù)據(jù)庫連接

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

          */

          private boolean testConnection(Connection conn) {

          try {

          // 判斷測(cè)試表是否存在

          if (testTable.equals("")) {

          // 如果測(cè)試表為空,試著使用此連接的 setAutoCommit() 方法

          // 來判斷連接否可用(此方法只在部分?jǐn)?shù)據(jù)庫可用,如果不可用 ,

          // 拋出異常)。注意:使用測(cè)試表的方法更可靠

          conn.setAutoCommit(true);

          } else {// 有測(cè)試表的時(shí)候使用測(cè)試表測(cè)試

          //check if this connection is valid

          Statement stmt = conn.createStatement();

          stmt.execute("select count(*) from " + testTable);

          }

          } catch (SQLException e) {

          // 上面拋出異常,此連接己不可用,關(guān)閉它,并返回 false;

          closeConnection(conn);

          return false;

          }

          // 連接可用,返回 true

          return true;

          }

          /**

          * 此函數(shù)返回一個(gè)數(shù)據(jù)庫連接到連接池中,并把此連接置為空閑。

          * 所有使用連接池獲得的數(shù)據(jù)庫連接均應(yīng)在不使用此連接時(shí)返回它。

          *

          * @param 需返回到連接池中的連接對(duì)象

          */

          public void returnConnection(Connection conn) {

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

          if (connections == null) {

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

          return;

          }

          PooledConnection pConn = null;

          Enumeration enum = connections.elements();

          // 遍歷連接池中的所有連接,找到這個(gè)要返回的連接對(duì)象

          while (enum.hasMoreElements()) {

          pConn = (PooledConnection) enum.nextElement();

          // 先找到連接池中的要返回的連接對(duì)象

          if (conn == pConn.getConnection()) {

          // 找到了 , 設(shè)置此連接為空閑狀態(tài)

          pConn.setBusy(false);

          break;

          }

          }

          }

          /**

          * 刷新連接池中所有的連接對(duì)象

          *

          */

          public synchronized void refreshConnections() throws SQLException {

          // 確保連接池己創(chuàng)新存在

          if (connections == null) {

          System.out.println(" 連接池不存在,無法刷新 !");

          return;

          }

          PooledConnection pConn = null;

          Enumeration enum = connections.elements();

          while (enum.hasMoreElements()) {

          // 獲得一個(gè)連接對(duì)象

          pConn = (PooledConnection) enum.nextElement();

          // 如果對(duì)象忙則等 5 秒 ,5 秒后直接刷新

          if (pConn.isBusy()) {

          wait(5000); // 等 5 秒

          }

          // 關(guān)閉此連接,用一個(gè)新的連接代替它。

          closeConnection(pConn.getConnection());

          pConn.setConnection(newConnection());

          pConn.setBusy(false);

          }

          }

          /**

          * 關(guān)閉連接池中所有的連接,并清空連接池。

          */

          public synchronized void closeConnectionPool() throws SQLException {

          // 確保連接池存在,如果不存在,返回

          if (connections == null) {

          System.out.println(" 連接池不存在,無法關(guān)閉 !");

          return;

          }

          PooledConnection pConn = null;

          Enumeration enum = connections.elements();

          while (enum.hasMoreElements()) {

          pConn = (PooledConnection) enum.nextElement();

          // 如果忙,等 5 秒

          if (pConn.isBusy()) {

          wait(5000); // 等 5 秒

          }

          //5 秒后直接關(guān)閉它

          closeConnection(pConn.getConnection());

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

          connections.removeElement(pConn);

          }

          // 置連接池為空

          connections = null;

          }

          /**

          * 關(guān)閉一個(gè)數(shù)據(jù)庫連接

          *

          * @param 需要關(guān)閉的數(shù)據(jù)庫連接

          */

          private void closeConnection(Connection conn) {

          try {

          conn.close();

          }catch (SQLException e) {

          System.out.println(" 關(guān)閉數(shù)據(jù)庫連接出錯(cuò): "+e.getMessage());

          }

          }

          /**

          * 使程序等待給定的毫秒數(shù)

          *

          * @param 給定的毫秒數(shù)

          */

          private void wait(int mSeconds) {

          try {

          Thread.sleep(mSeconds);

          } catch (InterruptedException e) {

          }

          }

          /**

          *

          * 內(nèi)部使用的用于保存連接池中連接對(duì)象的類

          * 此類中有兩個(gè)成員,一個(gè)是數(shù)據(jù)庫的連接,另一個(gè)是指示此連接是否

          * 正在使用的標(biāo)志。

          */

          class PooledConnection {

          Connection connection = null;// 數(shù)據(jù)庫連接

          boolean busy = false; // 此連接是否正在使用的標(biāo)志,默認(rèn)沒有正在使用

          // 構(gòu)造函數(shù),根據(jù)一個(gè) Connection 構(gòu)告一個(gè) PooledConnection 對(duì)象

          public PooledConnection(Connection connection) {

          this.connection = connection;

          }

          // 返回此對(duì)象中的連接

          public Connection getConnection() {

          return connection;

          }

          // 設(shè)置此對(duì)象的,連接

          public void setConnection(Connection connection) {

          this.connection = connection;

          }

          // 獲得對(duì)象連接是否忙

          public boolean isBusy() {

          return busy;

          }

          // 設(shè)置對(duì)象的連接正在忙

          public void setBusy(boolean busy) {

          this.busy = busy;

          }

          }

          }

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

          posted on 2007-09-06 18:15 禮物 閱讀(270) 評(píng)論(0)  編輯  收藏 所屬分類: java
          主站蜘蛛池模板: 虹口区| 上栗县| 泸定县| 大庆市| 沈阳市| 汉阴县| 怀宁县| 海口市| 西吉县| 盐城市| 洛宁县| 光泽县| 冷水江市| 海口市| 城口县| 华容县| 禹州市| 延津县| 阿拉善左旗| 宁都县| 清水河县| 凤山市| 邵东县| 新建县| 石柱| 揭东县| 武义县| 巴塘县| 穆棱市| 禄丰县| 凤阳县| 阿克苏市| 宝丰县| 安塞县| 潞城市| 余干县| 石门县| 沙田区| 新和县| 历史| 承德县|