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使用连接池的一般过程 二具体实现 DBConnectionManagerjava程序清单如下 import javaio*; import javasql*; import javautil*; import javautilDate; /** * 管理类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) poolsget(name); if (pool != null) { poolfreeConnection(con); } } /** * 获得一个可用的(空闲的)连接如果没有可用连接且已有连接数小于最大连接数 * 限制则创建并返回新连接 * * @param name 在属性文件中定义的连接池名字 * @return Connection 可用连接或null */ public Connection getConnection(String name) { DBConnectionPool pool = (DBConnectionPool) poolsget(name); if (pool != null) { return poolgetConnection(); } return null; } /** * 获得一个可用连接若没有可用连接且已有连接数小于最大连接数限制 * 则创建并返回新连接否则在指定的时间内等待其它线程释放连接 * * @param name 连接池名字 * @param time 以毫秒计的等待时间 * @return Connection 可用连接或null */ public Connection getConnection(String name long time) { DBConnectionPool pool = (DBConnectionPool) poolsget(name); if (pool != null) { return poolgetConnection(time); } return null; } /** * 关闭所有连接撤销驱动程序的注册 */ public synchronized void release() { // 等待直到最后一个客户程序调用 if (clients != ) { return; } Enumeration allPools = poolselements(); while (allPoolshasMoreElements()) { DBConnectionPool pool = (DBConnectionPool) allPoolsnextElement(); poolrelease(); } Enumeration allDrivers = driverselements(); while (allDrivershasMoreElements()) { Driver driver = (Driver) allDriversnextElement(); try { DriverManagerderegisterDriver(driver); log(撤销JDBC驱动程序 + drivergetClass()getName()+的注册); } catch (SQLException e) { log(e 无法撤销下列JDBC驱动程序的注册: + drivergetClass()getName()); } } } /** * 根据指定属性创建连接池实例 * * @param props 连接池属性 */ private void createPools(Properties props) { Enumeration propNames = propspropertyNames(); while (propNameshasMoreElements()) { String name = (String) propNamesnextElement(); if (nameendsWith(url)) { String poolName = namesubstring( namelastIndexOf()); String url = propsgetProperty(poolName + url); if (url == null) { log(没有为连接池 + poolName + 指定URL); continue; } String user = propsgetProperty(poolName + user); String password = propsgetProperty(poolName + password); String maxconn = propsgetProperty(poolName + maxconn ); int max; try { max = IntegervalueOf(maxconn)intValue(); } catch (NumberFormatException e) { log(错误的最大连接数限制: + maxconn + 连接池: + poolName); max = ; } DBConnectionPool pool = new DBConnectionPool(poolName url user password max); poolsput(poolName pool); log(成功创建连接池 + poolName); } } } /** * 读取属性完成初始化 */ private void init() { InputStream is = getClass()getResourceAsStream(/dbproperties); Properties dbProps = new Properties(); try { dbPropsload(is); } catch (Exception e) { Systemerrprintln(不能读取属性文件 + 请确保dbproperties在CLASSPATH指定的路径中); return; } String logFile = dbPropsgetProperty(logfile DBConnectionManagerlog); try { log = new PrintWriter(new FileWriter(logFile true) true); } catch (I |