無論是怎樣的應(yīng)用系統(tǒng),都無法脫離對資源的管理和使用。而對于持久層而言,資源的合理管理和調(diào)度則顯得尤為重要。

在大多所應(yīng)用系統(tǒng)中,80%以上的應(yīng)用邏輯并不需要特別復(fù)雜的數(shù)據(jù)訪問邏輯(可能只是幾條簡單的Select或者Insert/Update語句)。對于這些占大多數(shù)的簡單邏輯而言,如果SQL語句和數(shù)據(jù)庫本身的設(shè)計不是太糟糕(合理的關(guān)聯(lián),字段索引以及數(shù)據(jù)庫分區(qū)策略),在特定的硬件環(huán)境下,我們認(rèn)為數(shù)據(jù)庫的性能基本穩(wěn)定,但對于大型業(yè)務(wù)系統(tǒng),即使在特定的硬件環(huán)境下,并且數(shù)據(jù)庫設(shè)計良好也會存在性能低下的問題。那么問題出在哪里呢?

由于每次數(shù)據(jù)庫訪問時都獲取一個獨(dú)立的數(shù)據(jù)庫連接,代碼在每個操作中都獨(dú)立獲取一個數(shù)據(jù)庫連接進(jìn)行操作,最后在依次關(guān)閉,可以想見,一個業(yè)務(wù)操作中如果多次重復(fù)這樣的過程,對于系統(tǒng)來說是多么大的性能開銷啊!

如何解決這樣的問題呢?我們使用數(shù)據(jù)庫連接池機(jī)制(Connection Pool)

即使對于我們而言,通過JDBC獲取連接池實(shí)在是件再簡單不過的事情,但對于JDBC Driver來說,連接數(shù)據(jù)庫卻并非一件輕松差事,數(shù)據(jù)庫連接不僅僅是在應(yīng)用服務(wù)器與數(shù)據(jù)庫服務(wù)器之間建立一個Socket Connection(對于Type4JDBC Driver而言),連接建立之后,應(yīng)用服務(wù)器和數(shù)據(jù)庫服務(wù)器之間需要交換若干次數(shù)據(jù)(驗(yàn)證用戶密碼、權(quán)限等),然后,數(shù)據(jù)庫開始初始化連接會話句柄,記錄聯(lián)機(jī)日志,為此連接分配相應(yīng)的處理進(jìn)程和系統(tǒng)資源。

系統(tǒng)如此忙碌,如果我們知識簡單扔過去兩個SQL語句,然后就將次連接拋棄,實(shí)在可惜,而數(shù)據(jù)庫連接池技術(shù)正是為了解決這個問題。

數(shù)據(jù)庫連接池的基本原理是在內(nèi)部對象池中維護(hù)一定數(shù)量的數(shù)據(jù)庫連接,并對外暴露數(shù)據(jù)庫連接獲取和返回方法。

外部使用者可通過getConnection方法獲取連接,使用完畢后再通過releaseConnection方法將連接返回,注意此時連接并沒有關(guān)閉,而是由連接池管理器收回,并為下一次使用做好準(zhǔn)備。

數(shù)據(jù)庫連接池技術(shù)帶來下面的優(yōu)勢:

1:資源重用

由于數(shù)據(jù)庫連接池連接得以重用,避免了頻繁創(chuàng)建,釋放連接引起的大量性能開銷。在減少系統(tǒng)消耗的基礎(chǔ)上,另一方面也增進(jìn)了系統(tǒng)運(yùn)行環(huán)境的平穩(wěn)性(減少內(nèi)存碎片以及數(shù)據(jù)庫臨時進(jìn)程/線程的數(shù)量)

2:更快的系統(tǒng)響應(yīng)速度

數(shù)據(jù)庫連接池在初始化過程中,往往已經(jīng)創(chuàng)建了若干數(shù)據(jù)庫連接置于池中備用。此時連接的初始化工作均已完成。對于業(yè)務(wù)請求處理而言,直接利用現(xiàn)有可用連接,避免了數(shù)據(jù)庫連接初始化和釋放過程的時間開銷,從而縮減了系統(tǒng)整體響應(yīng)時間。

3:新的資源分配手段

對于多應(yīng)用共享同一數(shù)據(jù)庫的系統(tǒng)而言,可在應(yīng)用層通過數(shù)據(jù)庫連接池的配置,實(shí)現(xiàn)某一應(yīng)用作大可用數(shù)據(jù)庫連接數(shù)的限制,避免某一應(yīng)用獨(dú)占所有數(shù)據(jù)庫資源。

4:統(tǒng)一的連接管理,避免數(shù)據(jù)庫連接泄露

在較為完備的數(shù)據(jù)庫連接池實(shí)現(xiàn)中,可根據(jù)預(yù)先的連接占用超時設(shè)定,強(qiáng)制收回被占用連接。從而避免了常規(guī)數(shù)據(jù)庫連接操作中可能出現(xiàn)的資源泄露。

接下來介紹一個連接池的簡單實(shí)現(xiàn)。

package com.phy.emis.db;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.util.ResourceBundle;
import java.util.Vector;

public final class Pool {

    
private static String CONFIG = "db";
    
private static Vector vConnPool = new Vector();

    
private static int intMaxConnections = 20;
    
private static int iRetryTimes = 3;
    
private static String strDriver;
    
private static String strUrl;
    
private static String strUser;
    
private static String strPWD;
    
private static String strDataBase;
    
private static ResourceBundle rb;
    
public static boolean blnDebug;

    
private static int intClients = 0;
    
private static int intNew = 0, intGet = 0, intPut = 0;

    
static {
        
try {
            rb 
= ResourceBundle.getBundle(CONFIG);
           
            strDriver 
= rb.getString("driver"); //驅(qū)動程序字符串
            strUrl = rb.getString("url"); //url字符串
            strUser = rb.getString("user"); //登陸數(shù)據(jù)庫用戶名
            strPWD = rb.getString("pwd"); //登陸數(shù)據(jù)庫密碼
            strDataBase = rb.getString("database");

            
if (rb.getString("debug").equals("true")) {
                blnDebug 
= true;
            }

            
else {
                blnDebug 
= false;

            }

            intMaxConnections 
= Integer.parseInt(rb.getString("MaxConnection"));
            iRetryTimes 
= Integer.parseInt(rb.getString("DBRetryTimes"));

        }

        
catch (Exception e) {
            System.out.println(
"不能讀取屬性文件" + e);
        }

    }


    
//新建一個數(shù)據(jù)庫連接
    private static synchronized Connection newConnection() {
        intNew
++;
        Connection conn 
= null;
        
//System.out.println("new conn:" + intNew);
        
//初始化數(shù)據(jù)庫驅(qū)動程序
        try {
            Driver cnnDriver 
= (Driver) Class.forName(strDriver).newInstance();
            DriverManager.registerDriver(cnnDriver);
        }

        
catch (Exception e) {
            System.out.println(
"error happened at init driver  " + e);
        }


        
//新建一個連接
        try {
            conn 
= DriverManager.getConnection(strUrl, strUser, strPWD);
            conn.setCatalog(strDataBase);
        }

        
catch (Exception e) {
            
if (blnDebug) {
                System.out.print(e.getMessage());
            }

            
return null;
        }


        
return conn;
    }


    
//從連接池中獲得一個連接
    public static synchronized Connection getConnection() {
        intGet
++;
//System.out.println("get conn:" + intGet);
        Connection conn = null;
        
int iIndex = -1;
        
boolean bClosed;
        
int iCnt = 0;
//System.out.println("new:"+intNew+" getCNN:"+intGet+" client:"+intClients);
        while (iCnt < vConnPool.size()) {
            conn 
= (Connection) vConnPool.elementAt(iCnt);

            
if (conn == null//連接為空,從連接池中移出
                vConnPool.removeElementAt(iCnt);
                
continue;
            }

            
else //不為空
                try {

                    
if (conn.isClosed()) //連接已經(jīng)被關(guān)閉,從連接池中移出
                        vConnPool.removeElementAt(iCnt);
                        
continue;
                    }

                    
else //有效連接,得到連接在連接池中的位置
                        iIndex = iCnt;
                        
break;
                    }

                }

                
catch (Exception e) {
                    vConnPool.removeElementAt(iCnt);
                    
continue;
                }

            }
 //end else
        }
 //end while

        
if (iIndex != -1//已經(jīng)得到連接,從連接池移出
            vConnPool.removeElementAt(iIndex);
            intClients
++;
        }

        
else {
            
if (intClients < intMaxConnections) //沒有得到連接:如果連接池未滿,新建一個連接
                conn = newConnection(); //新建連接
                if (conn != null{
                    intClients
++;
                }

            }

            
else {
                
return null;
            }

        }
 //end if

        
return conn;
    }


    
/*****
     * 輔助方法,用于得到數(shù)據(jù)庫重試的次數(shù)
     * 
@param none
     * 
@return int 次數(shù)
     
*/

    
public static int getRetryTimes(){
        
return iRetryTimes;
    }


    
//將一個連接放入連接池中
    public static synchronized void putConnection(Connection conn) {
        intPut
++;
        
boolean bClosed;

        
try {
            bClosed 
= conn.isClosed();
        }

        
catch (Exception e) {
            bClosed 
= true;
        }


        
if (conn != null && !bClosed) {
            vConnPool.addElement(conn);
        }


        
if (intClients > 0{
            intClients
--;
        }

    }


    
//回收所有的連接
    protected void finalize() {
        
try {
            
for (int i = 0; i < vConnPool.size(); i++{
                Connection conn 
= (Connection) vConnPool.elementAt(i);
                conn.close();
            }

        }

        
catch (Exception e) {
        }

    }


    
//打印當(dāng)前數(shù)據(jù)庫的連接池的相關(guān)信息,以便調(diào)試
    public static String prtMsg(String strIn){
        String strRet 
= "<< MSG >> intClients:"+intClients+" intNew:"+
                         intNew
+" Get:"+intGet+" Put:"+intPut + " $$" + strIn ;
        
if(blnDebug){
            System.out.println(strRet);
        }

        
return strRet ;
    }


    
//打印當(dāng)前數(shù)據(jù)庫的連接池的相關(guān)信息,以便調(diào)試
    public static String prtMsg(){
        String strRet 
= "<< MSG >> intClients:"+intClients+" intNew:"+
                         intNew
+" Get:"+intGet+" Put:"+intPut ;
        
if(blnDebug){
            System.out.println(strRet);
        }

        
return strRet ;
    }


    
public static void processInvaildConn(){
        
for(int i=0;i<vConnPool.size();i++){
            Connection conn 
= (Connection) vConnPool.get(0);
            
try {
                conn.close();
                vConnPool.remove(conn);
                
//intNew --;
            }

            
catch(Exception e) {
                System.out.println(
"Error at processInvaildConn!"+e);
            }

        }
 //end for
        System.out.println("From Pool:The connection has been reset by peer!");
        intClients 
= 0;
        intNew 
= 0;
        intGet 
= 0;
        intPut 
= 0;
        System.out.println(
"From Pool:Init Connection!!");
    }


}