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

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

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

    zhyiwww
    用平實的筆,記錄編程路上的點點滴滴………
    posts - 536,comments - 394,trackbacks - 0

    用連接池提高 Servlet 訪問數據庫的效率(轉載)

    ?

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

    ?

    ?

    一、實現連接池的意義

    ?

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

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

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

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

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

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

    DBConnectionPool 提供以下功能:

    ?

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

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

    3) 在系統關閉時釋放所有資源,關閉所有連接。

    ?

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

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

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

    ?

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

    2) 根據在屬性文件中定義的屬性創建連接池對象。

    3) 實現連接池名字與其實例之間的映射。

    4) 跟蹤客戶程序對連接池的引用,保證在最后一個客戶程序結束時安全地關閉所有連接池。

    ?

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

    ?

    ?

    二、具體實現

    ?

    DBConnectionManager.java 程序清單如下:

    ?

    001 import java.io.*;

    002 import java.sql.*;

    003 import java.util.*;

    004 import java.util.Date;

    005

    006 /**

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

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

    009 */

    010 public class DBConnectionManager {

    011 static private DBConnectionManager instance; // 唯一實例

    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 * 返回唯一實例 . 如果是第一次調用此方法 , 則創建實例

    020 *

    021 * @return DBConnectionManager 唯一實例

    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 * 建構函數私有以防止其它對象創建本類實例

    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 * 獲得一個可用的 ( 空閑的 ) 連接 . 如果沒有可用連接 , 且已有連接數小于最大連接數

    053 * 限制 , 則創建并返回新連接

    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 * 獲得一個可用連接 . 若沒有可用連接 , 且已有連接數小于最大連接數限制 ,

    068 * 則創建并返回新連接 . 否則 , 在指定的時間內等待其它線程釋放連接 .

    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 * 關閉所有連接 , 撤銷驅動程序的注冊

    084 */

    085 public synchronized void release() {

    086 // 等待直到最后一個客戶程序調用

    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 驅動程序 " + driver.getClass().getName()+" 的注冊 ");

    102 }

    103 catch (SQLException e) {

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

    105 }

    106 }

    107 }

    108

    109 /**

    110 * 根據指定屬性創建連接池實例 .

    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(" 錯誤的最大連接數限制 : " + maxconn + " . 連接池 : " + poolName);

    134 max = 0;

    135 }

    136 DBConnectionPool pool =

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

    138 pools.put(poolName, pool);

    139 log(" 成功創建連接池 " + 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 驅動程序

    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 驅動程序 " + driverClassName);

    186 }

    187 catch (Exception e) {

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

    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 * 此內部類定義了一個連接池 . 它能夠根據要求創建新連接 , 直到預定的最

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

    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 * 創建新的連接池

    224 *

    225 * @param name 連接池名字

    226 * @param URL 數據庫的 JDBC URL

    227 * @param user 數據庫帳號 , null

    228 * @param password 密碼 , null

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

    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 * 從連接池獲得一個可用連接 . 如沒有空閑的連接且當前連接數小于最大連接

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

    255 * 然后遞歸調用自己以嘗試新的可用連接 .

    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 // 遞歸調用自己 , 嘗試再次獲取可用連接

    267 con = getConnection();

    268 }

    269 }

    270 catch (SQLException e) {

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

    272 // 遞歸調用自己 , 嘗試再次獲取可用連接

    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 * 關閉所有連接

    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(" 關閉連接池 " + name+" 中的一個連接 ");

    317 }

    318 catch (SQLException e) {

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

    320 }

    321 }

    322 freeConnections.removeAllElements();

    323 }

    324

    325 /**

    326 * 創建新的連接

    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+" 創建一個新的連接 ");

    338 }

    339 catch (SQLException e) {

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

    341 return null;

    342 }

    343 return con;

    344 }

    345 }

    346 }

    轉自:動態網制作指南 www.knowsky.com



    |----------------------------------------------------------------------------------------|
                               版權聲明  版權所有 @zhyiwww
                引用請注明來源 http://www.tkk7.com/zhyiwww   
    |----------------------------------------------------------------------------------------|
    posted on 2006-06-02 19:08 zhyiwww 閱讀(351) 評論(0)  編輯  收藏 所屬分類: j2ee
    主站蜘蛛池模板: 亚洲国产精品自产在线播放| av成人免费电影| 亚洲av无码国产精品色在线看不卡 | 色噜噜AV亚洲色一区二区| 亚洲一区二区三区免费观看| 色婷婷综合缴情综免费观看| 亚洲欧美不卡高清在线| 亚洲欧洲国产精品久久| 久久精品国产亚洲av成人| 国产av无码专区亚洲国产精品 | 免费的黄色网页在线免费观看| 亚洲国产电影在线观看| 亚洲AV无码不卡在线播放| 亚洲深深色噜噜狠狠网站| 337p日本欧洲亚洲大胆色噜噜| 亚洲啪啪AV无码片| 久久精品国产亚洲AV大全| 亚洲中文字幕无码久久精品1| 亚洲日本视频在线观看| 日本高清不卡中文字幕免费| 成人免费在线看片| 日韩欧毛片免费视频| 免费一级特黄特色大片在线| 又爽又黄无遮挡高清免费视频| 亚洲一区二区三区首页| 免费的黄色网页在线免费观看| 免费精品国产自产拍在线观看图片 | 亚洲av无码成人黄网站在线观看 | 91av免费观看| 日韩版码免费福利视频| 久久亚洲免费视频| 亚洲国产最大av| 精品熟女少妇aⅴ免费久久 | 国产成人免费网站| 国产特级淫片免费看| 亚洲专区在线视频| 日本亚洲免费无线码| 国产精品亚洲综合五月天| 午夜国产精品免费观看| 亚洲精品高清国产一久久| 亚洲国产无线乱码在线观看|