<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    zhyiwww
    用平實(shí)的筆,記錄編程路上的點(diǎn)點(diǎn)滴滴………
    posts - 536,comments - 394,trackbacks - 0

    用連接池提高 Servlet 訪問數(shù)據(jù)庫的效率(轉(zhuǎn)載)

    ?

    Java Servlet 作為首選的服務(wù)器端數(shù)據(jù)處理技術(shù),正在迅速取代 CGI 腳本。 Servlet 超越 CGI 的優(yōu)勢之一在于,不僅多個請求可以共享公用資源,而且還可以在不同用戶請求之間保留持續(xù)數(shù)據(jù)。本文介紹一種充分發(fā)揮該特色的實(shí)用技術(shù),即數(shù)據(jù)庫連接池。

    ?

    ?

    一、實(shí)現(xiàn)連接池的意義

    ?

    動態(tài) Web 站點(diǎn)往往用數(shù)據(jù)庫存儲的信息生成 Web 頁面,每一個頁面請求導(dǎo)致一次數(shù)據(jù)庫訪問。連接數(shù)據(jù)庫不僅要開銷一定的通訊和內(nèi)存資源,還必須完成用戶驗(yàn)證、安全上下文配置這類任務(wù),因而往往成為最為耗時的操作。當(dāng)然,實(shí)際的連接時間開銷千變?nèi)f化,但 1 2 秒延遲并非不常見。如果某個基于數(shù)據(jù)庫的 Web 應(yīng)用只需建立一次初始連

    接,不同頁面請求能夠共享同一連接,就能獲得顯著的性能改善。

    Servlet 是一個 Java 類。 Servlet 引擎(它可能是 Web 服務(wù)軟件的一部分,也可能是一個獨(dú)立的附加模塊)在系統(tǒng)啟動或 Servlet 第一次被請求時將該類裝入 Java 虛擬機(jī)并創(chuàng)建它的一個實(shí)例。不同用戶請求由同一 Servlet 實(shí)例的多個獨(dú)立線程處理。那些要

    求在不同請求之間持續(xù)有效的數(shù)據(jù)既可以用 Servlet 的實(shí)例變量來保存,也可以保存在獨(dú)立的輔助對象中。

    JDBC 訪問數(shù)據(jù)庫首先要創(chuàng)建與數(shù)據(jù)庫之間的連接,獲得一個連接對象( Connection ),由連接對象提供執(zhí)行 SQL 語句的方法。

    本文介紹的數(shù)據(jù)庫連接池包括一個管理類 DBConnectionManager ,負(fù)責(zé)提供與多個連接池對象( DBConnectionPool 類)之間的接口。每一個連接池對象管理一組 JDBC 連接對象,每一個連接對象可以被任意數(shù)量的 Servlet 共享。

    DBConnectionPool 提供以下功能:

    ?

    1) 從連接池獲取(或創(chuàng)建)可用連接。

    2) 把連接返回給連接池。

    3) 在系統(tǒng)關(guān)閉時釋放所有資源,關(guān)閉所有連接。

    ?

    此外, DBConnectionPool 類還能夠處理無效連接(原來登記為可用的連接,由于某種原因不再可用,如超時,通訊問題)

    ,并能夠限制連接池中的連接總數(shù)不超過某個預(yù)定值。

    管理類 DBConnectionManager 用于管理多個連接池對象,它提供以下功能:

    ?

    1) 裝載和注冊 JDBC 驅(qū)動程序。

    2) 根據(jù)在屬性文件中定義的屬性創(chuàng)建連接池對象。

    3) 實(shí)現(xiàn)連接池名字與其實(shí)例之間的映射。

    4) 跟蹤客戶程序?qū)B接池的引用,保證在最后一個客戶程序結(jié)束時安全地關(guān)閉所有連接池。

    ?

    本文余下部分將詳細(xì)說明這兩個類,最后給出一個示例演示 Servlet 使用連接池的一般過程。

    ?

    ?

    二、具體實(shí)現(xiàn)

    ?

    DBConnectionManager.java 程序清單如下:

    ?

    001 import java.io.*;

    002 import java.sql.*;

    003 import java.util.*;

    004 import java.util.Date;

    005

    006 /**

    007 * 管理類 DBConnectionManager 支持對一個或多個由屬性文件定義的數(shù)據(jù)庫連接

    008 * 池的訪問 . 客戶程序可以調(diào)用 getInstance() 方法訪問本類的唯一實(shí)例 .

    009 */

    010 public class DBConnectionManager {

    011 static private DBConnectionManager instance; // 唯一實(shí)例

    012 static private int clients;

    013

    014 private Vector drivers = new Vector();

    015 private PrintWriter log;

    016 private Hashtable pools = new Hashtable();

    017

    018 /**

    019 * 返回唯一實(shí)例 . 如果是第一次調(diào)用此方法 , 則創(chuàng)建實(shí)例

    020 *

    021 * @return DBConnectionManager 唯一實(shí)例

    022 */

    023 static synchronized public DBConnectionManager getInstance() {

    024 if (instance == null) {

    025 instance = new DBConnectionManager();

    026 }

    027 clients++;

    028 return instance;

    029 }

    030

    031 /**

    032 * 建構(gòu)函數(shù)私有以防止其它對象創(chuàng)建本類實(shí)例

    033 */

    034 private DBConnectionManager() {

    035 init();

    036 }

    037

    038 /**

    039 * 將連接對象返回給由名字指定的連接池

    040 *

    041 * @param name 在屬性文件中定義的連接池名字

    042 * @param con 連接對象

    043 */

    044 public void freeConnection(String name, Connection con) {

    045 DBConnectionPool pool = (DBConnectionPool) pools.get(name);

    046 if (pool != null) {

    047 pool.freeConnection(con);

    048 }

    049 }

    050

    051 /**

    052 * 獲得一個可用的 ( 空閑的 ) 連接 . 如果沒有可用連接 , 且已有連接數(shù)小于最大連接數(shù)

    053 * 限制 , 則創(chuàng)建并返回新連接

    054 *

    055 * @param name 在屬性文件中定義的連接池名字

    056 * @return Connection 可用連接或 null

    057 */

    058 public Connection getConnection(String name) {

    059 DBConnectionPool pool = (DBConnectionPool) pools.get(name);

    060 if (pool != null) {

    061 return pool.getConnection();

    062 }

    063 return null;

    064 }

    065

    066 /**

    067 * 獲得一個可用連接 . 若沒有可用連接 , 且已有連接數(shù)小于最大連接數(shù)限制 ,

    068 * 則創(chuàng)建并返回新連接 . 否則 , 在指定的時間內(nèi)等待其它線程釋放連接 .

    069 *

    070 * @param name 連接池名字

    071 * @param time 以毫秒計的等待時間

    072 * @return Connection 可用連接或 null

    073 */

    074 public Connection getConnection(String name, long time) {

    075 DBConnectionPool pool = (DBConnectionPool) pools.get(name);

    076 if (pool != null) {

    077 return pool.getConnection(time);

    078 }

    079 return null;

    080 }

    081

    082 /**

    083 * 關(guān)閉所有連接 , 撤銷驅(qū)動程序的注冊

    084 */

    085 public synchronized void release() {

    086 // 等待直到最后一個客戶程序調(diào)用

    087 if (--clients != 0) {

    088 return;

    089 }

    090

    091 Enumeration allPools = pools.elements();

    092 while (allPools.hasMoreElements()) {

    093 DBConnectionPool pool = (DBConnectionPool) allPools.nextElement();

    094 pool.release();

    095 }

    096 Enumeration allDrivers = drivers.elements();

    097 while (allDrivers.hasMoreElements()) {

    098 Driver driver = (Driver) allDrivers.nextElement();

    099 try {

    100 DriverManager.deregisterDriver(driver);

    101 log(" 撤銷 JDBC 驅(qū)動程序 " + driver.getClass().getName()+" 的注冊 ");

    102 }

    103 catch (SQLException e) {

    104 log(e, " 無法撤銷下列 JDBC 驅(qū)動程序的注冊 : " + driver.getClass().getName());

    105 }

    106 }

    107 }

    108

    109 /**

    110 * 根據(jù)指定屬性創(chuàng)建連接池實(shí)例 .

    111 *

    112 * @param props 連接池屬性

    113 */

    114 private void createPools(Properties props) {

    115 Enumeration propNames = props.propertyNames();

    116 while (propNames.hasMoreElements()) {

    117 String name = (String) propNames.nextElement();

    118 if (name.endsWith(".url")) {

    119 String poolName = name.substring(0, name.lastIndexOf("."));

    120 String url = props.getProperty(poolName + ".url");

    121 if (url == null) {

    122 log(" 沒有為連接池 " + poolName + " 指定 URL");

    123 continue;

    124 }

    125 String user = props.getProperty(poolName + ".user");

    126 String password = props.getProperty(poolName + ".password");

    127 String maxconn = props.getProperty(poolName + ".maxconn", "0");

    128 int max;

    129 try {

    130 max = Integer.valueOf(maxconn).intValue();

    131 }

    132 catch (NumberFormatException e) {

    133 log(" 錯誤的最大連接數(shù)限制 : " + maxconn + " . 連接池 : " + poolName);

    134 max = 0;

    135 }

    136 DBConnectionPool pool =

    137 new DBConnectionPool(poolName, url, user, password, max);

    138 pools.put(poolName, pool);

    139 log(" 成功創(chuàng)建連接池 " + poolName);

    140 }

    141 }

    142 }

    143

    144 /**

    145 * 讀取屬性完成初始化

    146 */

    147 private void init() {

    148 InputStream is = getClass().getResourceAsStream("/db.properties");

    149 Properties dbProps = new Properties();

    150 try {

    151 dbProps.load(is);

    152 }

    153 catch (Exception e) {

    154 System.err.println(" 不能讀取屬性文件 . " +

    155 " 請確保 db.properties CLASSPATH 指定的路徑中 ");

    156 return;

    157 }

    158 String logFile = dbProps.getProperty("logfile", "DBConnectionManager.log");

    159 try {

    160 log = new PrintWriter(new FileWriter(logFile, true), true);

    161 }

    162 catch (IOException e) {

    163 System.err.println(" 無法打開日志文件 : " + logFile);

    164 log = new PrintWriter(System.err);

    165 }

    166 loadDrivers(dbProps);

    167 createPools(dbProps);

    168 }

    169

    170 /**

    171 * 裝載和注冊所有 JDBC 驅(qū)動程序

    172 *

    173 * @param props 屬性

    174 */

    175 private void loadDrivers(Properties props) {

    176 String driverClasses = props.getProperty("drivers");

    177 StringTokenizer st = new StringTokenizer(driverClasses);

    178 while (st.hasMoreElements()) {

    179 String driverClassName = st.nextToken().trim();

    180 try {

    181 Driver driver = (Driver)

    182 Class.forName(driverClassName).newInstance();

    183 DriverManager.registerDriver(driver);

    184 drivers.addElement(driver);

    185 log(" 成功注冊 JDBC 驅(qū)動程序 " + driverClassName);

    186 }

    187 catch (Exception e) {

    188 log(" 無法注冊 JDBC 驅(qū)動程序 : " +

    189 driverClassName + ", 錯誤 : " + e);

    190 }

    191 }

    192 }

    193

    194 /**

    195 * 將文本信息寫入日志文件

    196 */

    197 private void log(String msg) {

    198 log.println(new Date() + ": " + msg);

    199 }

    200

    201 /**

    202 * 將文本信息與異常寫入日志文件

    203 */

    204 private void log(Throwable e, String msg) {

    205 log.println(new Date() + ": " + msg);

    206 e.printStackTrace(log);

    207 }

    208

    209 /**

    210 * 此內(nèi)部類定義了一個連接池 . 它能夠根據(jù)要求創(chuàng)建新連接 , 直到預(yù)定的最

    211 * 大連接數(shù)為止 . 在返回連接給客戶程序之前 , 它能夠驗(yàn)證連接的有效性 .

    212 */

    213 class DBConnectionPool {

    214 private int checkedOut;

    215 private Vector freeConnections = new Vector();

    216 private int maxConn;

    217 private String name;

    218 private String password;

    219 private String URL;

    220 private String user;

    221

    222 /**

    223 * 創(chuàng)建新的連接池

    224 *

    225 * @param name 連接池名字

    226 * @param URL 數(shù)據(jù)庫的 JDBC URL

    227 * @param user 數(shù)據(jù)庫帳號 , null

    228 * @param password 密碼 , null

    229 * @param maxConn 此連接池允許建立的最大連接數(shù)

    230 */

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

    232 int maxConn) {

    233 this.name = name;

    234 this.URL = URL;

    235 this.user = user;

    236 this.password = password;

    237 this.maxConn = maxConn;

    238 }

    239

    240 /**

    241 * 將不再使用的連接返回給連接池

    242 *

    243 * @param con 客戶程序釋放的連接

    244 */

    245 public synchronized void freeConnection(Connection con) {

    246 // 將指定連接加入到向量末尾

    247 freeConnections.addElement(con);

    248 checkedOut--;

    249 notifyAll();

    250 }

    251

    252 /**

    253 * 從連接池獲得一個可用連接 . 如沒有空閑的連接且當(dāng)前連接數(shù)小于最大連接

    254 * 數(shù)限制 , 則創(chuàng)建新連接 . 如原來登記為可用的連接不再有效 , 則從向量刪除之 ,

    255 * 然后遞歸調(diào)用自己以嘗試新的可用連接 .

    256 */

    257 public synchronized Connection getConnection() {

    258 Connection con = null;

    259 if (freeConnections.size() > 0) {

    260 // 獲取向量中第一個可用連接

    261 con = (Connection) freeConnections.firstElement();

    262 freeConnections.removeElementAt(0);

    263 try {

    264 if (con.isClosed()) {

    265 log(" 從連接池 " + name+" 刪除一個無效連接 ");

    266 // 遞歸調(diào)用自己 , 嘗試再次獲取可用連接

    267 con = getConnection();

    268 }

    269 }

    270 catch (SQLException e) {

    271 log(" 從連接池 " + name+" 刪除一個無效連接 ");

    272 // 遞歸調(diào)用自己 , 嘗試再次獲取可用連接

    273 con = getConnection();

    274 }

    275 }

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

    277 con = newConnection();

    278 }

    279 if (con != null) {

    280 checkedOut++;

    281 }

    282 return con;

    283 }

    284

    285 /**

    286 * 從連接池獲取可用連接 . 可以指定客戶程序能夠等待的最長時間

    287 * 參見前一個 getConnection() 方法 .

    288 *

    289 * @param timeout 以毫秒計的等待時間限制

    290 */

    291 public synchronized Connection getConnection(long timeout) {

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

    293 Connection con;

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

    295 try {

    296 wait(timeout);

    297 }

    298 catch (InterruptedException e) {}

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

    300 // wait() 返回的原因是超時

    301 return null;

    302 }

    303 }

    304 return con;

    305 }

    306

    307 /**

    308 * 關(guān)閉所有連接

    309 */

    310 public synchronized void release() {

    311 Enumeration allConnections = freeConnections.elements();

    312 while (allConnections.hasMoreElements()) {

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

    314 try {

    315 con.close();

    316 log(" 關(guān)閉連接池 " + name+" 中的一個連接 ");

    317 }

    318 catch (SQLException e) {

    319 log(e, " 無法關(guān)閉連接池 " + name+" 中的連接 ");

    320 }

    321 }

    322 freeConnections.removeAllElements();

    323 }

    324

    325 /**

    326 * 創(chuàng)建新的連接

    327 */

    328 private Connection newConnection() {

    329 Connection con = null;

    330 try {

    331 if (user == null) {

    332 con = DriverManager.getConnection(URL);

    333 }

    334 else {

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

    336 }

    337 log(" 連接池 " + name+" 創(chuàng)建一個新的連接 ");

    338 }

    339 catch (SQLException e) {

    340 log(e, " 無法創(chuàng)建下列 URL 的連接 : " + URL);

    341 return null;

    342 }

    343 return con;

    344 }

    345 }

    346 }

    轉(zhuǎn)自:動態(tài)網(wǎng)制作指南 www.knowsky.com



    |----------------------------------------------------------------------------------------|
                               版權(quán)聲明  版權(quán)所有 @zhyiwww
                引用請注明來源 http://m.tkk7.com/zhyiwww   
    |----------------------------------------------------------------------------------------|
    posted on 2006-06-02 19:08 zhyiwww 閱讀(351) 評論(0)  編輯  收藏 所屬分類: j2ee
    主站蜘蛛池模板: 99在线视频免费| 国产特黄一级一片免费| 精品无码免费专区毛片| 国产亚洲福利精品一区| 高清永久免费观看| 国产成人精品日本亚洲| 久久免费福利视频| 亚洲六月丁香六月婷婷色伊人| 免费国产成人高清在线观看网站| 亚洲精品天堂在线观看| 国产资源免费观看| 成在线人直播免费视频| 中文字幕精品亚洲无线码一区 | 亚洲国产成人精品青青草原| 青青青免费国产在线视频小草| 亚洲国产成人无码AV在线影院| 国产精品久免费的黄网站| 男女男精品网站免费观看| 不卡一卡二卡三亚洲| 特级无码毛片免费视频尤物| 亚洲国产视频网站| 国产一级理论免费版| 久久久免费观成人影院| 久久久久亚洲AV无码专区首JN | 国产91色综合久久免费| 亚洲精品国产第一综合99久久| 亚洲免费日韩无码系列 | 亚洲精品免费在线观看| 亚洲精品免费网站| 中文字幕亚洲日韩无线码| 91手机看片国产永久免费| 亚洲AV无码专区亚洲AV桃| 亚洲人成网站观看在线播放| 亚洲免费精彩视频在线观看| 亚洲gay片在线gv网站| 亚洲成A人片777777| 成人在线视频免费| 国色精品va在线观看免费视频| 国产成+人+综合+亚洲专| 亚洲一区无码精品色| 114一级毛片免费|