一種完成數(shù)據(jù)庫(kù)連接池的方法(1)
發(fā)表時(shí)間:2023-08-20 來(lái)源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]數(shù)據(jù)庫(kù)連接池在編寫(xiě)應(yīng)用服務(wù)是經(jīng)常需要用到的模塊,太過(guò)頻繁的連接數(shù)據(jù)庫(kù)對(duì)服務(wù)性能來(lái)講是一個(gè)瓶頸,使用緩沖池技術(shù)可以來(lái)消除這個(gè)瓶頸。我們可以在互聯(lián)網(wǎng)上找到很多關(guān)于數(shù)據(jù)庫(kù)連接池的源程序,但是都發(fā)現(xiàn)這樣一個(gè)...
數(shù)據(jù)庫(kù)連接池在編寫(xiě)應(yīng)用服務(wù)是經(jīng)常需要用到的模塊,太過(guò)頻繁的連接數(shù)據(jù)庫(kù)對(duì)服務(wù)性能來(lái)講是一個(gè)瓶頸,使用緩沖池技術(shù)可以來(lái)消除這個(gè)瓶頸。我們可以在互聯(lián)網(wǎng)上找到很多關(guān)于數(shù)據(jù)庫(kù)連接池的源程序,但是都發(fā)現(xiàn)這樣一個(gè)共同的問(wèn)題:這些連接池的實(shí)現(xiàn)方法都不同程度地增加了與使用者之間的耦合度。很多的連接池都要求用戶(hù)通過(guò)其規(guī)定的方法獲取數(shù)據(jù)庫(kù)的連接,這一點(diǎn)我們可以理解,畢竟目前所有的應(yīng)用服務(wù)器取數(shù)據(jù)庫(kù)連接的方式都是這種方式實(shí)現(xiàn)的。但是另外一個(gè)共同的問(wèn)題是,它們同時(shí)不允許使用者顯式的調(diào)用Connection.close()方法,而需要用其規(guī)定的一個(gè)方法來(lái)關(guān)閉連接。這種做法有兩個(gè)缺點(diǎn):
第一:改變了用戶(hù)使用習(xí)慣,增加了用戶(hù)的使用難度。
首先我們來(lái)看看一個(gè)正常的數(shù)據(jù)庫(kù)操作過(guò)程:
int executeSQL(String sql) throws SQLException
{
Connection conn = getConnection();//通過(guò)某種方式獲取數(shù)據(jù)庫(kù)連接
PreparedStatement ps = null;
int res = 0;
try{
ps = conn.prepareStatement(sql);
res = ps.executeUpdate();
}finally{
try{
ps.close();
}catch(Exception e){}
try{
conn.close();//
}catch(Exception e){}
}
return res;
}
使用者在用完數(shù)據(jù)庫(kù)連接后通常是直接調(diào)用連接的方法close來(lái)釋放數(shù)據(jù)庫(kù)資源,如果用我們前面提到的連接池的實(shí)現(xiàn)方法,那語(yǔ)句conn.close()將被某些特定的語(yǔ)句所替代。
第二:使連接池?zé)o法對(duì)之中的所有連接進(jìn)行獨(dú)占控制。由于連接池不允許用戶(hù)直接調(diào)用連接的close方法,一旦使用者在使用的過(guò)程中由于習(xí)慣問(wèn)題直接關(guān)閉了數(shù)據(jù)庫(kù)連接,那么連接池將無(wú)法正常維護(hù)所有連接的狀態(tài),考慮連接池和應(yīng)用由不同開(kāi)發(fā)人員實(shí)現(xiàn)時(shí)這種問(wèn)題更容易出現(xiàn)。
綜合上面提到的兩個(gè)問(wèn)題,我們來(lái)討論一下如何解決這兩個(gè)要命的問(wèn)題。
首先我們先設(shè)身處地的考慮一下用戶(hù)是想怎么樣來(lái)使用這個(gè)數(shù)據(jù)庫(kù)連接池的。用戶(hù)可以通過(guò)特定的方法來(lái)獲取數(shù)據(jù)庫(kù)的連接,同時(shí)這個(gè)連接的類(lèi)型應(yīng)該是標(biāo)準(zhǔn)的java.sql.Connection。用戶(hù)在獲取到這個(gè)數(shù)據(jù)庫(kù)連接后可以對(duì)這個(gè)連接進(jìn)行任意的操作,包括關(guān)閉連接等。
通過(guò)對(duì)用戶(hù)使用的描述,怎樣可以接管Connection.close方法就成了我們這篇文章的主題。
為了接管數(shù)據(jù)庫(kù)連接的close方法,我們應(yīng)該有一種類(lèi)似于鉤子的機(jī)制。例如在Windows編程中我們可以利用Hook API來(lái)實(shí)現(xiàn)對(duì)某個(gè)Windows API的接管。在JAVA中同樣也有這樣一個(gè)機(jī)制。JAVA提供了一個(gè)Proxy類(lèi)和一個(gè)InvocationHandler,這兩個(gè)類(lèi)都在java.lang.reflect包中。我們先來(lái)看看SUN公司提供的文檔是怎么描述這兩個(gè)類(lèi)的。
public interface InvocationHandler
InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler.
When a method is invoked on a proxy instance,
the method invocation is encoded and dispatched to the invoke method of its invocation handler.
SUN的API文檔中關(guān)于Proxy的描述很多,這里就不羅列出來(lái)。通過(guò)文檔對(duì)接口InvocationHandler的描述我們可以看到當(dāng)調(diào)用一個(gè)Proxy實(shí)例的方法時(shí)會(huì)觸發(fā)Invocationhanlder的invoke方法。從JAVA的文檔中我們也同時(shí)了解到這種動(dòng)態(tài)代理機(jī)制只能接管接口的方法,而對(duì)一般的類(lèi)無(wú)效,考慮到j(luò)ava.sql.Connection本身也是一個(gè)接口由此就找到了解決如何接管close方法的出路。
首先,我們先定義一個(gè)數(shù)據(jù)庫(kù)連接池參數(shù)的類(lèi),定義了數(shù)據(jù)庫(kù)的JDBC驅(qū)動(dòng)程序類(lèi)名,連接的URL以及用戶(hù)名口令等等一些信息,該類(lèi)是用于初始化連接池的參數(shù),具體定義如下:
public class ConnectionParam implements Serializable
{
private String driver;//數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序
private String url;//數(shù)據(jù)連接的URL
private String user;//數(shù)據(jù)庫(kù)用戶(hù)名
private String password;//數(shù)據(jù)庫(kù)密碼
private int minConnection = 0;//初始化連接數(shù)
private int maxConnection = 50;//最大連接數(shù)
private long timeoutValue = 600000;//連接的最大空閑時(shí)間
private long waitTime = 30000;//取連接的時(shí)候如果沒(méi)有可用連接最大的等待時(shí)間