JDBC
Java Servlet作為首選的服務器端數據處理技術
正在迅速取代CGI腳本
Servlet超越CGI的優勢之一在於
不僅多個請求可以共享公用資源
而且還可以在不同用戶請求之間保留持續數據
本文介紹一種充分發揮該特色的實用技術
即數據庫連接池
一
實現連接池的意義
動態Web站點往往用數據庫存儲的信息生成Web頁面
每一個頁面請求導致一次數據庫訪問
連接數據庫不僅要開銷一定的通訊和內存資源
還必須完成用戶驗證
安全上下文配置這類任務
因而往往成為最為耗時的操作
當然
實際的連接時間開銷千變萬化
但
到
秒延遲並非不常見
如果某個基於數據庫的Web應用只需建立一次初始連接
不同頁面請求能夠共享同一連接
就能獲得顯著的性能改善
Servlet是一個Java類
Servlet引擎(它可能是Web服務軟件的一部分
也可能是一個獨立的附加模塊)在系統啟動或Servlet第一次被請求時將該類裝入Java虛擬機並創建它的一個實例
不同用戶請求由同一Servlet實例的多個獨立線程處理
那些要求在不同請求之間持續有效的數據既可以用Servlet的實例變量來保存
也可以保存在獨立的輔助對象中
用JDBC訪問數據庫首先要創建與數據庫之間的連接
獲得一個連接對象(Connection)
由連接對象提供執行SQL語句的方法
本文介紹的數據庫連接池包括一個管理類DBConnectionManager
負責提供與多個連接池對象(DBConnectionPool類)之間的接口
每一個連接池對象管理一組JDBC連接對象
每一個連接對象可以被任意數量的Servlet共享
類DBConnectionPool提供以下功能
) 從連接池獲取(或創建)可用連接
) 把連接返回給連接池
) 在系統關閉時釋放所有資源
關閉所有連接
此外
DBConnectionPool類還能夠處理無效連接(原來登記為可用的連接
由於某種原因不再可用
如超時
通訊問題)
並能夠限制連接池中的連接總數不超過某個預定值
管理類DBConnectionManager用於管理多個連接池對象
它提供以下功能
) 裝載和注冊JDBC驅動程序
) 根據在屬性文件中定義的屬性創建連接池對象
) 實現連接池名字與其實例之間的映射
) 跟蹤客戶程序對連接池的引用
保證在最後一個客戶程序結束時安全地關閉所有連接池
本文余下部分將詳細說明這兩個類
最後給出一個示例演示Servlet使用連接池的一般過程
二
具體實現
DBConnectionManager
java程序清單如下
import java
io
*;
import java
sql
*;
import java
util
*;
import java
util
Date;
/**
* 管理類DBConnectionManager支持對一個或多個由屬性文件定義的數據庫連接
* 池的訪問
客戶程序可以調用getInstance()方法訪問本類的唯一實例
*/
public class DBConnectionManager {
static private DBConnectionManager instance; // 唯一實例
static private int clients;
private Vector drivers = new Vector();
private PrintWriter log;
private Hashtable pools = new Hashtable();
/**
* 返回唯一實例
如果是第一次調用此方法
則創建實例
*
* @return DBConnectionManager 唯一實例
*/
static synchronized public DBConnectionManager getInstance() {
if (instance == null) {
instance = new DBConnectionManager();
}
clients++;
return instance;
}
/**
* 建構函數私有以防止其它對象創建本類實例
*/
private DBConnectionManager() {
init();
}
/**
* 將連接對象返回給由名字指定的連接池
*
* @param name 在屬性文件中定義的連接池名字
* @param con 連接對象
*/
public void freeConnection(String name
Connection con) {
DBConnectionPool pool = (DBConnectionPool) pools
get(name);
if (pool != null) {
pool
freeConnection(con);
}
}
/**
* 獲得一個可用的(空閒的)連接
如果沒有可用連接
且已有連接數小於最大連接數
* 限制
則創建並返回新連接
*
* @param name 在屬性文件中定義的連接池名字
* @return Connection 可用連接或null
*/
public Connection getConnection(String name) {
DBConnectionPool pool = (DBConnectionPool) pools
get(name);
if (pool != null) {
return pool
getConnection();
}
return null;
}
/**
* 獲得一個可用連接
若沒有可用連接
且已有連接數小於最大連接數限制
* 則創建並返回新連接
否則
在指定的時間內等待其它線程釋放連接
*
* @param name 連接池名字
* @param time 以毫秒計的等待時間
* @return Connection 可用連接或null
*/
public Connection getConnection(String name
long time) {
DBConnectionPool pool = (DBConnectionPool) pools
get(name);
if (pool != null) {
return pool
getConnection(time);
}
return null;
}
/**
* 關閉所有連接
撤銷驅動程序的注冊
*/
public synchronized void release() {
// 等待直到最後一個客戶程序調用
if (
clients !=
) {
return;
}
Enumeration allPools = pools
elements();
while (allPools
hasMoreElements()) {
DBConnectionPool pool = (DBConnectionPool) allPools
nextElement();
pool
release();
}
Enumeration allDrivers = drivers
elements();
while (allDrivers
hasMoreElements()) {
Driver driver = (Driver) allDrivers
nextElement();
try {
DriverManager
deregisterDriver(driver);
log(
撤銷JDBC驅動程序
+ driver
getClass()
getName()+
的注冊
);
}
catch (SQLException e) {
log(e
無法撤銷下列JDBC驅動程序的注冊:
+ driver
getClass()
getName());
}
}
}
/**
* 根據指定屬性創建連接池實例
*
* @param props 連接池屬性
*/
private void createPools(Properties props) {
Enumeration propNames = props
propertyNames();
while (propNames
hasMoreElements()) {
String name = (String) propNames
nextElement();
if (name
endsWith(
url
)) {
String poolName = name
substring(
name
lastIndexOf(
));
String url = props
getProperty(poolName +
url
);
if (url == null) {
log(
沒有為連接池
+ poolName +
指定URL
);
continue;
}
String user = props
getProperty(poolName +
user
);
String password = props
getProperty(poolName +
password
);
String maxconn = props
getProperty(poolName +
maxconn
);
int max;
try {
max = Integer
valueOf(maxconn)
intValue();
}
catch (NumberFormatException e) {
log(
錯誤的最大連接數限制:
+ maxconn +
連接池:
+ poolName);
max =
;
}
DBConnectionPool pool =
new DBConnectionPool(poolName
url
user
password
max);
pools
put(poolName
pool);
log(
成功創建連接池
+ poolName);
}
}
}
/**
* 讀取屬性完成初始化
*/
private void init() {
InputStream is = getClass()
getResourceAsStream(
/db
properties
);
Properties dbProps = new Properties();
try {
dbProps
load(is);
}
catch (Exception e) {
System
err
println(
不能讀取屬性文件
+
請確保db
properties在CLASSPATH指定的路徑中
);
return;
}
String logFile = dbProps
getProperty(
logfile
DBConnectionManager
log
);
try {
log = new PrintWriter(new FileWriter(logFile
true)
true);
}
catch (I
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19437.html