top
Loading...
Servlet中jdbc應用高級篇(三)

DBConnectionPool類代表一個由url標識的數據庫連接池。前面,我們已經提到,jdbc的url由三個部分組成:協議標識(總是jdbc),子協議標識(例如,odbc.oracle),和數據庫標識(跟特定的數據庫有關)。連接池也具有一個名字,供客戶程序引用。另外,連接池還有一個用戶名,一個密碼和一個最大允許連接數。如果web應用允許所有的用戶使用某些數據庫操作,而另一些操作是有限制的,則可以創建兩個連接池,具有同樣的url,不同的user name和password,分別處理兩類不同的操作權限。現把DBConnectionPool詳細介紹如下:

一、DBConnectionPool的構造


構造函數取得上述的所有參數:

public DBConnectionPool(String name, String URL, String user,

String password, int maxConn) {

this.name = name;

this.URL = URL;

this.user = user;

this.password = password;

this.maxConn = maxConn;

}

將所有的參數保存在實例變量中。


二、從池中打開一個連接


DBConnectionPool提供兩種方法來檢查連接。兩種方法都返回一個可用的連接,如果沒有多余的連接,則創建一個新的連接。如果最大連接數已經達到,第一個方法返回null,第二個方法則等待一個連接被其他進程釋放。

public synchronized Connection getConnection() {

Connection con = null;

if (freeConnections.size() > 0) {

// Pick the first Connection in the Vector

// to get round-robin usage

con = (Connection) freeConnections.firstElement();

freeConnections.removeElementAt(0);

try {

if (con.isClosed()) {

log("Removed bad connection from " + name);

// Try again recursively

con = getConnection();

}

}

catch (SQLException e) {

log("Removed bad connection from " + name);

// Try again recursively

con = getConnection();

}

}

else if (maxConn == 0 || checkedOut < maxConn) {

con = newConnection();

}

if (con != null) {

checkedOut++;

}

return con;

}

所有空閑的連接對象保存在一個叫freeConnections 的Vector中。如果存在至少一個空閑的連接,getConnection()返回其中第一個連接。下面,將會看到,進程釋放的連接返回到freeConnections的末尾。這樣,最大限度地避免了數據庫因一個連接不活動而意外將其關閉的風險。

再返回客戶之前,isClosed()檢查連接是否有效。如果連接被關閉了,或者一個錯誤發生,該方法遞歸調用取得另一個連接。

如果沒有可用的連接,該方法檢查是否最大連接數被設置為0表示無限連接數,或者達到了最大連接數。如果可以創建新的連接,則創建一個新的連接。否則,返回null。

方法newConnection()用來創建一個新的連接。這是一個私有方法,基于用戶名和密碼來確定是否可以創建新的連接。

private Connection newConnection() {

Connection con = null;

try {

if (user == null) {

con = DriverManager.getConnection(URL);

}

else {

con = DriverManager.getConnection(URL, user, password);

}

log("Created a new connection in pool " + name);

}

catch (SQLException e) {

log(e, "Can not create a new connection for " + URL);

return null;

}

return con;

}

jdbc的DriverManager提供一系列的getConnection()方法,可以使用url和用戶名,密碼等參數創建一個連接。

第二個getConnection()方法帶有一個超時參數 timeout,當該參數指定的毫秒數表示客戶愿意為一個連接等待的時間。這個方法調用前一個方法。


public synchronized Connection getConnection(long timeout) {

long startTime = new Date().getTime();

Connection con;

while ((con = getConnection()) == null) {

try {

wait(timeout);

}

catch (InterruptedException e) {}

if ((new Date().getTime() - startTime) >= timeout) {

// Timeout has expired

return null;

}

}

return con;

}


局部變量startTime初始化當前的時間。一個while循環首先嘗試獲得一個連接,如果失敗,wait()函數被調用來等待需要的時間。后面會看到,Wait()函數會在另一個進程調用notify()或者notifyAll()時返回,或者等到時間流逝完畢。為了確定wait()是因為何種原因返回,我們用開始時間減去當前時間,檢查是否大于timeout。如果結果大于timeout,返回null,否則,在此調用getConnection()函數。


四、將一個連接返回池中


DBConnectionPool類中有一個freeConnection方法以返回的連接作為參數,將連接返回連接池。


public synchronized void freeConnection(Connection con) {

// Put the connection at the end of the Vector

freeConnections.addElement(con);

checkedOut--;

notifyAll();

}

連接被加在freeConnections向量的最后,占用的連接數減1,調用notifyAll()函數通知其他等待的客戶現在有了一個連接。

五、關閉


大多數servlet引擎提供完整的關閉方法。數據庫連接池需要得到通知以正確地關閉所有的連接。DBConnectionManager負責協調關閉事件,但連接由各個連接池自己負責關閉。方法relase()由DBConnectionManager調用。
public synchronized void release() {

Enumeration allConnections = freeConnections.elements();

while (allConnections.hasMoreElements()) {

Connection con = (Connection) allConnections.nextElement();

try {

con.close();

log("Closed connection for pool " + name);

}

catch (SQLException e) {

log(e, "Can not close connection for pool " + name);

}

}

freeConnections.removeAllElements();

}

本方法遍歷freeConnections向量以關閉所有的連接。

?BR>
作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗