??xml version="1.0" encoding="utf-8" standalone="yes"?> 一、实现连接池的意?/p> 动态Web站点往往用数据库存储的信息生成Web面Q每一个页面请求导致一ơ数据库讉K。连接数据库不仅要开销一定的通讯和内存资源,q必d成用户验证、安全上下文配置q类dQ因而往往成ؓ最时的操作。当Ӟ实际的连接时间开销千变万化Q但1?Ugqƈ非不常见。如果某个基于数据库的Web应用只需建立一ơ初始连 1) 从连接池获取Q或创徏Q可用连接?br> 2) 把连接返回给q接池?br> 3) 在系l关闭时释放所有资源,关闭所有连接?/p> 此外Q?DBConnectionPoolc还能够处理无效q接Q原来登Cؓ可用的连接,׃某种原因不再可用Q如时Q通讯问题Q?br> Qƈ能够限制q接池中的连接L不超q某个预定倹{?br> 理cDBConnectionManager用于理多个q接池对象,它提供以下功能: 1) 装蝲和注册JDBC驱动E序?br> 2) Ҏ在属性文件中定义的属性创接池对象?br> 3) 实现q接池名字与其实例之间的映射?br> 4) 跟踪客户E序对连接池的引用,保证在最后一个客L序结束时安全地关闭所有连接池?/p> 本文余下部分详l说明这两个c,最后给Z个示例演CServlet使用q接池的一般过E?br> 二、具体实?/p> DBConnectionManager.javaE序清单如下Q?/p> 001 import java.io.*; 该类?09?45行实玎ͼ它表C指向某个数据库的连接池。数据库由JDBC URL标识。一个JDBC URL׃部分l成Q协议标识(LjdbcQ,驱动E序标识Q如 odbc、idb、oracle{)Q数据库标识Q其格式依赖于驱动程序)。例如,jdbc:odbc:de 四、类DBConnectionManager 说明 该类只能创徏一个实例,其它对象能够调用光态方法(也称为类ҎQ获得该唯一实例的引用。如031?36行所C,DBConnectionManagercȝ建构函数是私有的Q这是ؓ了避免其它对象创cȝ实例?br> DBConnectionManagercȝ客户E序可以调用getInstance()Ҏ获得对该cd一实例的引用。如018?29行所C,cȝ唯一实例在getInstance()ҎW一ơ被调用期间创徏Q此后其引用׃直保存在静态变量instance中。每ơ调用getInstance() drivers 以空格分隔的JDBC驱动E序cd?br> logfile 日志文g的绝对\?/p> 其它的属性和特定q接池相养I其属性名字前应加上连接池名字Q?/p> <poolname>.url 数据库的 JDBC URL 其中url属性是必需的,而其它属性则是可选的。数据库帐号和密码必d法。用于Windowsq_的db.properties文gCZ drivers=sun.jdbc.odbc.JdbcOdbcDriver jdbc.idbDriver idb.url=jdbc:idb:c:\\local\\javawebserver1.1\\db\\db.prp access.url=jdbc:odbc:demo 注意在Windows路径中的反斜杠必输?个,q是׃属性文件中的反斜杠同时也是一个{义字W?br> init()Ҏ在创建属性对象ƈddb.properties文g之后Q就开始检查logfile属性。如果属性文件中没有指定日志文gQ则默认为当前目录下的DBConnectionManager.log文g。如日志文g无法使用Q则向System.err输出日志记录?br> 装蝲和注册所有在drivers属性中指定的JDBC驱动E序?70?92行之间的loadDrivers()Ҏ实现。该Ҏ先用StringTokenizerdrivers属性值分割ؓ对应于驱动程序名U的字符Ԍ然后依次装蝲q些cdƈ创徏其实例,最后在 DriverManager中注?br> 该实例ƈ把它加入C个私有的向量drivers。向量drivers用于关闭服务时从DriverManager取消所有JDBC 驱动E序的注册?br> init()Ҏ的最后一个Q务是调用U有ҎcreatePools()创徏q接池对象。如109?42行所C,createPools()Ҏ先创建所有属性名字的枚D对象Q即Enumeration对象Q该对象可以惌Z个元素系列,逐次调用其nextElement()Ҏ顺序返 五、Servlet使用q接池示?/p> Servlet API所定义的Servlet生命周期cdQ?/p> 1) 创徏q初始化ServletQinit()ҎQ?br> 2) 响应客户E序的服务请求(service()ҎQ?br> 3) Servletl止q行Q释放所有资源(destroy()ҎQ?/p> 本例演示q接池应用,上述关键步骤中的相关操作为: 1) 在init()Q用实例变量connMgr 保存调用DBConnectionManager.getInstance()所q回的引用?br> 2) 在service()Q调用getConnection()Q执行数据库操作Q用freeConnection()连接返回给q接池?br> 3) 在destroy()Q调用release()关闭所有连接,释放所有资源?/p> CZE序清单如下Q?/p> import java.io.*; public void init(ServletConfig conf) throws ServletException { public void service(HttpServletRequest req, HttpServletResponse res) res.setContentType("text/html"); public void destroy() {
1、连接池模型
本文讨论的连接池包括一个连接池c(DBConnectionPoolQ和一个连接池理c(DBConnetionPoolManagerQ。连接池cLҎ一数据库所有连接的“缓冲池”,主要实现以下功能Q①从连接池获取或创建可用连接;②用完毕之后,把连接返q给q接池;③在pȝ关闭前,断开所有连接ƈ释放q接占用的系l资源;④还能够处理无效q接Q原来登Cؓ可用的连接,׃某种原因不再可用Q如时Q通讯问题Q,q能够限制连接池中的q接L不低于某个预定值和不超q某个预定倹{?BR>
q接池管理类是连接池cȝ外覆c(wrapperQ?W合单例模式Q即pȝ中只能有一个连接池理cȝ实例。其主要用于对多个连接池对象的管理,h以下功能Q①装蝲q注册特定数据库的JDBC驱动E序Q②Ҏ属性文件给定的信息Q创接池对象Q③为方便管理多个连接池对象Qؓ每一个连接池对象取一个名字,实现q接池名字与其实例之间的映射Q④跟踪客户使用q接情况Q以侉K要是关闭q接释放资源。连接池理cȝ引入主要是ؓ了方便对多个q接池的使用和管理,如系l需要连接不同的数据库,或连接相同的数据库但׃安全性问题,需要不同的用户使用不同的名U和密码?BR>
2、连接池实现
下面l出q接池类和连接池理cȝ主要属性及所要实现的基本接口Q?BR>
public class DBConnectionPool implements TimerListener{
private int checkedOut;//已被分配出去的连接数
private ArrayList freeConnections = new ArrayList();//容器Q空闲池Q根?/创徏旉序存放已创Z未分配出去的连?BR>private int minConn;//q接池里q接的最数?BR>private int maxConn;//q接池里允许存在的最大连接数
private String name;//个连接池取个名字Q方便管?BR>private String password;//q接数据库时需要的密码
private String url;//所要创接的数据库的地址
private String user;//q接数据库时需要的用户?BR>public Timer timer;//定时?BR>public DBConnectionPool(String name, String URL, String user, String
password, int maxConn)//公开的构造函?BR>public synchronized void freeConnection(Connection con) //使用完毕之后Q?/把连接返q给I闲?BR>public synchronized Connection getConnection(long timeout)//得到一个连接,//timeout是等待时?BR>public synchronized void release()//断开所有连接,释放占用的系l资?BR>private Connection newConnection()//新徏一个数据库q接
public synchronized void TimerEvent() //定时器事件处理函?BR>
}
public class DBConnectionManager {
static private DBConnectionManager instance;//q接池管理类的唯一实例
static private int clients;//客户数量
private ArrayList drivers = new ArrayList();//容器Q存放数据库驱动E序
private HashMap pools = new HashMap ();//以name/value的Ş式存取连接池//对象的名字及q接池对?BR>static synchronized public DBConnectionManager getInstance()//如果唯一?/实例instance已经创徏Q直接返回这个实?否则Q调用私有构造函敎ͼ?/接池理cȝ唯一实例
private DBConnectionManager()//U有构造函?在其中调用初始化函数init()
public void freeConnection(String name, Connection con)// 释放一个连接,//name是一个连接池对象的名?BR>
public Connection getConnection(String name)//从名字ؓname的连接池对象//中得C个连?BR>
public Connection getConnection(String name, long time)//从名字ؓname
//的连接池对象中取得一个连接,time是等待时?BR>
public synchronized void release()//释放所有资?BR>
private void createPools(Properties props)//Ҏ属性文件提供的信息Q创?/一个或多个q接?BR>
private void init()//初始化连接池理cȝ唯一实例Q由U有构造函数调?BR>
private void loadDrivers(Properties props)//装蝲数据库驱动程?BR>
}
3、连接池使用
上面所实现的连接池在程序开发时如何应用到系l中呢?下面以ServletZ说明q接池的使用?BR>
Servlet的生命周期是Q在开始徏立servletӞ调用其初始化QinitQ方法。之后每个用戯求都D一个调用前面徏立的实例的serviceҎ的线E。最后,当服务器军_卸蝲一个servletӞ它首先调用该servlet?destroyҎ?BR>
Ҏservlet的特点,我们可以在初始化函数中生成连接池理cȝ唯一实例Q其中包括创Z个或多个q接池)。如Q?BR>
public void init() throws ServletException
{
connMgr = DBConnectionManager.getInstance();
}
然后可以在serviceҎ中通过q接池名UC用连接池Q执行数据库操作。最后在destroyҎ中释攑֍用的pȝ资源Q如Q?
public void destroy() {
connMgr.release(); super.destroy();
}
l束?/B>
在用JDBCq行与数据库有关的应用开发中Q数据库q接的管理是一个难炏V很多时候,q接的q理所造成的系l资源开销q大成ؓ制约大型企业U应用效率的瓉。对于众多用戯问的Web应用Q采用数据库q接技术的pȝ在效率和E_性上比采用传l的其他方式的系l要好很多。本文阐qC使用JDBC讉K数据库的技术﹑讨论了基于连接池技术的数据库连接管理的关键问题q给Z一个实现模型。文章所l出的是q接池管理程序的一U基本模式,为提高系l的整体性能Q在此基上还可以q行很多有意义的扩展?BR>
]]>
Java Servlet作ؓ首选的服务器端数据处理技术,正在q速取?a target="_blank" class="wordstyle">CGI脚本。Servlet越CGI的优势之一在于Q不仅多个请求可以共享公用资源,而且q可以在不同用户h之间保留持箋数据。本文介l一U充分发挥该特色的实用技术,x据库q接池?br>
接,不同面h能够׃n同一q接Q就能获得显著的性能改善?br> Servlet是一个JavacRServlet引擎Q它可能是Web服务软g的一部分Q也可能是一个独立的附加模块Q在pȝ启动或ServletW一ơ被h时将该类装入Java虚拟机ƈ创徏它的一个实例。不同用戯求由同一Servlet实例的多个独立线E处理。那些要
求在不同h之间持箋有效的数据既可以用Servlet的实例变量来保存Q也可以保存在独立的辅助对象中?br> 用JDBC讉K数据库首先要创徏与数据库之间的连接,获得一个连接对象(ConnectionQ,p接对象提供执行SQL语句的方法?br> 本文介绍的数据库q接池包括一个管理类DBConnectionManagerQ负责提供与多个q接池对象(DBConnectionPoolc)之间的接口。每一个连接池对象理一lJDBCq接对象Q每一个连接对象可以被L数量的Servlet׃n?br> cDBConnectionPool提供以下功能Q?/p>
002 import java.sql.*;
003 import java.util.*;
004 import java.util.Date;
005
006 /**
007 * 理cDBConnectionManager支持对一个或多个由属性文件定义的数据库连?br> 008 * 池的讉K.客户E序可以调用getInstance()Ҏ讉K本类的唯一实例.
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 * q回唯一实例.如果是第一ơ调用此Ҏ,则创建实?br> 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 * 建构函数U有以防止其它对象创建本cd?br> 033 */
034 private DBConnectionManager() {
035 init();
036 }
037
038 /**
039 * 连接对象返回给由名字指定的q接?br> 040 *
041 * @param name 在属性文件中定义的连接池名字
042 * @param con q接对象
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 * 获得一个可用的(I闲?q接.如果没有可用q接,且已有连接数于最大连接数
053 * 限制,则创建ƈq回新连?br> 054 *
055 * @param name 在属性文件中定义的连接池名字
056 * @return Connection 可用q接或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 * 则创建ƈq回新连?否则,在指定的旉内等待其它线E释放连?
069 *
070 * @param name q接池名?br> 071 * @param time 以毫U计的等待时?br> 072 * @return Connection 可用q接或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 * 关闭所有连?撤销驱动E序的注?br> 084 */
085 public synchronized void release() {
086 // {待直到最后一个客L序调?br> 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驱动E序 " + driver.getClass().getName()+"的注?quot;);
102 }
103 catch (SQLException e) {
104 log(e, "无法撤销下列JDBC驱动E序的注? " + driver.getClass().getName());
105 }
106 }
107 }
108
109 /**
110 * Ҏ指定属性创接池实例.
111 *
112 * @param props q接池属?br> 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 + " .q接? " + poolName);
134 max = 0;
135 }
136 DBConnectionPool pool =
137 new DBConnectionPool(poolName, url, user, password, max);
138 pools.put(poolName, pool);
139 log("成功创徏q接?quot; + poolName);
140 }
141 }
142 }
143
144 /**
145 * d属性完成初始化
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("不能d属性文? " +
155 "L保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("无法打开日志文g: " + logFile);
164 log = new PrintWriter(System.err);
165 }
166 loadDrivers(dbProps);
167 createPools(dbProps);
168 }
169
170 /**
171 * 装蝲和注册所有JDBC驱动E序
172 *
173 * @param props 属?br> 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驱动E序" + driverClassName);
186 }
187 catch (Exception e) {
188 log("无法注册JDBC驱动E序: " +
189 driverClassName + ", 错误: " + e);
190 }
191 }
192 }
193
194 /**
195 * 文本信息写入日志文?br> 196 */
197 private void log(String msg) {
198 log.println(new Date() + ": " + msg);
199 }
200
201 /**
202 * 文本信息与异常写入日志文g
203 */
204 private void log(Throwable e, String msg) {
205 log.println(new Date() + ": " + msg);
206 e.printStackTrace(log);
207 }
208
209 /**
210 * 此内部类定义了一个连接池.它能够根据要求创建新q接,直到预定的最
211 * 大连接数为止.在返回连接给客户E序之前,它能够验证连接的有效?
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 * 创徏新的q接?br> 224 *
225 * @param name q接池名?br> 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 * 不再用的q接q回l连接池
242 *
243 * @param con 客户E序释放的连?br> 244 */
245 public synchronized void freeConnection(Connection con) {
246 // 指定连接加入到向量末尾
247 freeConnections.addElement(con);
248 checkedOut--;
249 notifyAll();
250 }
251
252 /**
253 * 从连接池获得一个可用连?如没有空闲的q接且当前连接数于最大连?br> 254 * 数限?则创建新q接.如原来登Cؓ可用的连接不再有?则从向量删除?
255 * 然后递归调用自己以尝试新的可用连?
256 */
257 public synchronized Connection getConnection() {
258 Connection con = null;
259 if (freeConnections.size() > 0) {
260 // 获取向量中第一个可用连?br> 261 con = (Connection) freeConnections.firstElement();
262 freeConnections.removeElementAt(0);
263 try {
264 if (con.isClosed()) {
265 log("从连接池" + name+"删除一个无效连?quot;);
266 // 递归调用自己,试再次获取可用q接
267 con = getConnection();
268 }
269 }
270 catch (SQLException e) {
271 log("从连接池" + name+"删除一个无效连?quot;);
272 // 递归调用自己,试再次获取可用q接
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 * 从连接池获取可用q接.可以指定客户E序能够{待的最长时?br> 287 * 参见前一个getConnection()Ҏ.
288 *
289 * @param timeout 以毫U计的等待时间限?br> 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()q回的原因是时
301 return null;
302 }
303 }
304 return con;
305 }
306
307 /**
308 * 关闭所有连?br> 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("关闭q接?quot; + name+"中的一个连?quot;);
317 }
318 catch (SQLException e) {
319 log(e, "无法关闭q接?quot; + name+"中的q接");
320 }
321 }
322 freeConnections.removeAllElements();
323 }
324
325 /**
326 * 创徏新的q接
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("q接?quot; + name+"创徏一个新的连?quot;);
338 }
339 catch (SQLException e) {
340 log(e, "无法创徏下列URL的连? " + URL);
341 return null;
342 }
343 return con;
344 }
345 }
346 }
moQ即是一个指向demo数据库的JDBC URLQ而且讉K该数据库要用JDBC-ODBC驱动E序。每个连接池都有一个供客户E序使用的名字以及可选的用户帐号、密码、最大连接数限制。如果Web应用E序所支持的某些数据库操作可以被所有用h行,而其它一些操作应q别许可的用户执行Q则可以ZcL作分别定义连接池Q两个连接池使用相同的JDBC URLQ但使用不同的帐号和密码?br> cDBConnectionPool的徏构函数需要上q所有数据作为其参数。如222?38行所C,q些数据被保存ؓ它的实例变量Q?br> ?52?83行?85?05行所C, 客户E序可以使用DBConnectionPoolcL供的两个Ҏ获取可用q接。两者的共同之处在于Q如q接池中存在可用q接Q则直接q回Q否则创建新的连接ƈq回。如果没有可用连接且已有q接L{于最大限?br> 敎ͼW一个方法将直接q回nullQ而第二个Ҏ等待直到有可用q接为止?br> 所有的可用q接对象均登记在名ؓfreeConnections的向量(VectorQ中。如果向量中有多于一个的q接QgetConnection()L选取W一个。同Ӟ׃新的可用q接L从尾部加入向量,从而得数据库q接׃长时间闲|而被关闭的风险减低到最程度?br> W一个getConnection()在返回可用连接给客户E序之前Q调用了isClosed()Ҏ验证q接仍旧有效。如果该q接被关闭或触发异常QgetConnection()递归地调用自׃试获取另外的可用连接。如果在向量freeConnections中不存在M可用q?br> 接,getConnection()Ҏ查是否已l指定最大连接数限制。如已经指定Q则查当前连接数是否已经到达极限。此处maxConn?表示没有限制。如果没有指定最大连接数限制或当前连接数于该|该方法尝试创建新的连接。如创徏成功Q则增加已用连接的计数q返回,否则q回I倹{?br> ?25?45行所C,创徏新连接由newConnection()Ҏ实现。创E与是否已经指定数据库帐受密码有兟?br> JDBC的DriverManagercL供多个getConnection()ҎQ这些方法要用到JDBC URL与其它一些参敎ͼ如用户帐号和密码{?br> DriverManager用指定的JDBC URL定适合于目标数据库的驱动程序及建立q接?br> ?85?05行实现的W二个getConnection()Ҏ需要一个以毫秒为单位的旉参数Q该参数表示客户E序能够{待的最长时间。徏立连接的具体操作仍旧q一个getConnection()Ҏ实现?br> 该方法执行时先将startTime初始化ؓ当前旉。在while循环中尝试获得一个连接。如果失败,则以l定的时间gؓ参数调用wait()。wait()的返回可能是׃其它U程调用notify()或notifyAll()Q也可能是由于预定时间已到。ؓ扑ևwait()q回的真正原因,E序用当前时间减开始时_startTimeQ,如差值大于预定时间则q回I|否则再次调用getConnection()?br> 把空闲的q接登记到连接池?40?50行的freeConnection()Ҏ实现Q它的参Cؓq回l连接池的连接对象。该对象被加入到freeConnections向量的末,然后减少已用连接计数。调用notifyAll()是ؓ了通知其它正在{待可用q接的线E?br> 许多Servlet引擎为实现安全关闭提供多U方法。数据库q接池需要知道该事g以保证所有连接能够正常关闭。DBConnectionManagerc负协调整个关闭q程Q但关闭q接池中所有连接的d则由DBConnectionPoolc负责。在307?23行实现的release()Ҏ供DBConnectionManager调用。该Ҏ遍历freeConnections向量q关闭所有连接,然后从向量中删除q些q接?br>
都增加一个DBConnectionManager的客L序计数。即Q该计数代表引用DBConnectionManager唯一实例的客L序LQ它被用于控制q接池的关闭操作?br> 该类实例的初始化工作?46?68行之间的U有Ҏinit()完成。其?getResourceAsStream()Ҏ用于定位q打开外部文g。外部文件的定位Ҏ依赖于类装蝲器的实现。标准的本地c装载器查找操作L开始于cL件所在\径,也能够搜索CLASSPATH中声明的路径。db.properties是一个属性文Ӟ它包含定义连接池的键-值对。可供定义的公用属性如下:
<poolname>.maxconn 允许建立的最大连接数Q?表示没有限制
<poolname>.user 用于该连接池的数据库帐号
<poolname>.password 相应的密?/p>
如下Q?/p>
logfile=D:\\user\\src\\java\\DBConnectionManager\\log.txt
idb.maxconn=2
access.user=demo
access.password=demopw
回各元素Q,然后在其中搜索名字以?url”结属性。对于每一个符合条件的属性,先提取其q接池名字部分,q而读取所有属于该q接池的属性,最后创接池对象q把它保存在实例变量pools中。散列表QHashtablec?Qpools实现q接
池名字到q接池对象之间的映射Q此处以q接池名字ؓ键,q接池对象ؓ倹{?br> Z于客L序从指定q接池获得可用连接或连接返回给q接池,cDBConnectionManager提供了方法getConnection()和freeConnection()。所有这些方法都要求在参C指定q接池名字,具体的连接获取或q回操作则调用对应的q接池对象完成。它们的实现分别?51?64行?66?80行?38?49行?br> ?82?07行所C,为实现连接池的安全关闭,DBConnectionManager提供了方法release()。在上面我们已经提到Q所有DBConnectionManager的客L序都应该调用静态方法getInstance()以获得该理器的引用Q此调用增加客L序计数?br> 客户E序在关闭时调用release()可以递减该计数。当最后一个客L序调用release()Q递减后的引用计数?Q就可以调用各个q接池的release()Ҏ关闭所有连接了。管理类release()Ҏ最后的d是撤销所有JDBC驱动E序的注册?br>
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class TestServlet extends HttpServlet {
private DBConnectionManager connMgr;
super.init(conf);
connMgr = DBConnectionManager.getInstance();
}
throws IOException {
PrintWriter out = res.getWriter();
Connection con = connMgr.getConnection("idb");
if (con == null) {
out.println("不能获取数据库连?");
return;
}
ResultSet rs = null;
ResultSetMetaData md = null;
Statement stmt = null;
try {
stmt = con.createStatement();
rs = stmt.executeQuery("SELECT * FROM EMPLOYEE");
md = rs.getMetaData();
out.println("<H1>职工数据</H1>");
while (rs.next()) {
out.println("<BR>");
for (int i = 1; i < md.getColumnCount(); i++) {
out.print(rs.getString(i) + ", ");
}
}
stmt.close();
rs.close();
}
catch (SQLException e) {
e.printStackTrace(out);
}
connMgr.freeConnection("idb", con);
}
connMgr.release();
super.destroy();
}
}
]]>
]]>
testmysql.jsp如下Q?
< %@ page contentType="text/html;charset=gb2312"% >
< %@ page import="java.sql.*"% >
< html >
< body >
< %Class.forName("org.postgresql.Driver").newInstance();
String url ="jdbc:postgresql://localhost/soft"
//softZ的数据库?
String user="myuser";
String password="mypassword";
Connection conn= DriverManager.getConnection(url,user,password);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {% >
您的W一个字D内容ؓQ?lt; %=rs.getString(1)% >
您的W二个字D内容ؓQ?lt; %=rs.getString(2)% >
< %}% >
< %out.print("数据库操作成功,恭喜?);% >
< %rs.close();
stmt.close();
conn.close();
% >
< /body >
< /html >
文章出处Q?CSDN.NET
testmysql.jsp如下Q?
< %@ page contentType="text/html;charset=gb2312"% >
< %@ page import="java.sql.*"% >
< html >
< body >
< %Class.forName("org.gjt.mm.mysql.Driver").newInstance();
String url ="jdbc:mysql://localhost/softforum?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1"
//testDBZ的数据库?
Connection conn= DriverManager.getConnection(url);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {% >
您的W一个字D内容ؓQ?lt; %=rs.getString(1)% >
您的W二个字D内容ؓQ?lt; %=rs.getString(2)% >
< %}% >
< %out.print("数据库操作成功,恭喜?);% >
< %rs.close();
stmt.close();
conn.close();
% >
< /body >
< /html >
testinformix.jsp如下Q?
< %@ page contentType="text/html;charset=gb2312"% >
< %@ page import="java.sql.*"% >
< html >
< body >
< %Class.forName("com.informix.jdbc.IfxDriver").newInstance();
String url =
"jdbc:informix-sqli://123.45.67.89:1533/testDB:INFORMIXSERVER=myserver;
user=testuser;password=testpassword";
//testDBZ的数据库?
Connection conn= DriverManager.getConnection(url);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {% >
您的W一个字D内容ؓQ?lt; %=rs.getString(1)% >
您的W二个字D内容ؓQ?lt; %=rs.getString(2)% >
< %}% >
< %out.print("数据库操作成功,恭喜?);% >
< %rs.close();
stmt.close();
conn.close();
% >
< /body >
< /html >
testmysql.jsp如下Q?
< %@ page contentType="text/html;charset=gb2312"% >
< %@ page import="java.sql.*"% >
< html >
< body >
< %Class.forName("com.sybase.jdbc.SybDriver").newInstance();
String url =" jdbc:sybase:Tds:localhost:5007/tsdata";
//tsdataZ的数据库?
Properties sysProps = System.getProperties();
SysProps.put("user","userid");
SysProps.put("password","user_password");
Connection conn= DriverManager.getConnection(url, SysProps);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {% >
您的W一个字D内容ؓQ?lt; %=rs.getString(1)% >
您的W二个字D内容ؓQ?lt; %=rs.getString(2)% >
< %}% >
< %out.print("数据库操作成功,恭喜?);% >
< %rs.close();
stmt.close();
conn.close();
% >
< /body >
< /html >
testdb2.jsp如下Q?
< %@ page contentType="text/html;charset=gb2312"% >
< %@ page import="java.sql.*"% >
< html >
< body >
< %Class.forName("com.ibm.db2.jdbc.app.DB2Driver ").newInstance();
String url="jdbc:db2://localhost:5000/sample";
//sampleZ的数据库?
String user="admin";
String password="";
Connection conn= DriverManager.getConnection(url,user,password);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {% >
您的W一个字D内容ؓQ?lt; %=rs.getString(1)% >
您的W二个字D内容ؓQ?lt; %=rs.getString(2)% >
< %}% >
< %out.print("数据库操作成功,恭喜?);% >
< %rs.close();
stmt.close();
conn.close();
% >
< /body >
< /html >
testsqlserver.jsp如下Q?
< %@ page contentType="text/html;charset=gb2312"% >
< %@ page import="java.sql.*"% >
< html >
< body >
< %Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs";
//pubsZ的数据库?
String user="sa";
String password="";
Connection conn= DriverManager.getConnection(url,user,password);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {% >
您的W一个字D内容ؓQ?lt; %=rs.getString(1)% >
您的W二个字D内容ؓQ?lt; %=rs.getString(2)% >
< %}% >
< %out.print("数据库操作成功,恭喜?);% >
< %rs.close();
stmt.close();
conn.close();
% >
< /body >
< /html >
testoracle.jsp如下Q?
< %@ page contentType="text/html;charset=gb2312"% >
< %@ page import="java.sql.*"% >
< html >
< body >
< %Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
String url="jdbc:oracle:thin:@localhost:1521:orcl";
//orclZ的数据库的SID
String user="scott";
String password="tiger";
Connection conn= DriverManager.getConnection(url,user,password);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {% >
您的W一个字D内容ؓQ?lt; %=rs.getString(1)% >
您的W二个字D内容ؓQ?lt; %=rs.getString(2)% >
< %}% >
< %out.print("数据库操作成功,恭喜?);% >
< %rs.close();
stmt.close();
conn.close();
% >
< /body >
< /html >