java servlet 连接池_用连接池提高Servlet访问数据库的效率(转载)

用连接池提高

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.blogjava.net/zhyiwww

|----------------------------------------------------------------------------------------|

posted on 2006-06-02 19:08 zhyiwww 阅读(293) 评论(0)  编辑  收藏 所属分类: j2ee

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值