用连接池提高Servlet访问数据库的效率(2)
三、DBConnectionPool:连接池的管理者
在数据库操作的背后,隐藏着一种强大的机制——连接池。这种机制由DBConnectionPool类实现,位于代码的第209至345行。该类代表了一个指向特定数据库的连接池,这个数据库通过JDBC URL进行标识。JDBC URL结构独特,由三部分组成:协议标识(总是为jdbc)、驱动程序标识(如odbc、idb、oracle等),以及数据库标识(格式依赖于驱动程序)。例如,“jdbc:odbc:demo”就是一个指向demo数据库的JDBC URL,访问该数据库使用的是JDBC-ODBC驱动程序。
每个连接池都拥有一个名字,供客户程序使用,同时还有可选的用户账号、密码以及最大连接数限制。想象一下,如果你的Web应用程序支持多种数据库操作,有些操作对所有用户开放,而有些则需要特定权限,你就可以为这两类操作创建不同的连接池,共享同一个JDBC URL但使用不同的账号和密码。
DBConnectionPool类的构造函数需要上述所有数据作为参数。这些数据被妥善保存为实例变量(如第252至283行、285至305行所示)。客户程序可以通过DBConnectionPool类的两个方法获取可用的连接。如果连接池中有空闲连接,这两个方法都会直接返回;否则,它们会创建新的连接并返回。
其中,第一个getConnection()方法在返回连接前会验证其有效性。如果连接已关闭或出现异常,它会递归调用自己以尝试获取其他可用连接。创建新连接的任务由newConnection()方法实现(如第325至345行所示),这个过程会受到数据库账号和密码的影响。
DBConnectionPool还实现了一个机制来管理空闲的连接。当不再需要一个连接时,它会被放回连接池(通过freeConnection()方法,如第240至250行所示)。如果客户程序等待时间过长仍无法获取连接,getConnection()方法会尝试创建新的连接。如果创建失败,则返回空值。
四、DBConnectionManager:单一实例的管理者
在数据库连接的世界中,有一个类独树一帜——DBConnectionManager。这个类只创建一个实例,其他对象可以通过其静态方法获取这个唯一实例的引用(如第31至36行所示)。由于其构造函数的私有性质(为了避免其他对象创建该类的实例),这个类确保了其实例的唯一性。
DBConnectionManager类是一个关键的管理工具,专门负责处理数据库连接。为了获得这个类的唯一实例,客户程序会调用getInstance()方法。这个方法在首次被调用时创建类的唯一实例,并将其实例引用保存在静态变量instance中。每次调用getInstance()都会增加一个客户程序计数,这个计数代表着引用DBConnectionManager唯一实例的客户程序总数。这个计数对于控制连接池的关闭操作至关重要。
类的初始化工作由init()方法完成,该方法位于私有代码块中的146至168行。其中,getResourceAsStream()方法用于打开外部文件,类装载器则负责定位这些文件。标准的类装载器搜索操作始于类文件所在路径,同时也会搜索CLASSPATH中声明的路径。
db.properties是一个包含连接池相关键-值对的属性文件。其中一些公用属性包括drivers(指定JDBC驱动程序类列表)、logfile(日志文件的绝对路径)等。每个连接池都有自己的属性前缀,例如
在Windows平台上,db.properties文件的示例如下:
```makefile
drivers=sun.jdbc.odbc.JdbcOdbcDriver jdbc.idbDriver
logfile=D:\\user\\src\\java\\DBConnectionManager\\log.txt
idb.url=jdbc:idb:c:\\local\\javawebserver1.1\\db\\db.prpidb
idb.maxconn=2aess.url=jdbc:odbc:demoaess.user=demoaess.password=demopw
```
在init()方法中,除了创建属性对象并读取db.properties文件,还会检查logfile属性并设置日志文件路径。如果没有指定日志文件路径,则默认为当前目录下的DBConnectionManager.log文件。如果日志文件无法使用,则会将日志记录输出到System.err。init()还会调用loadDrivers()方法装载并注册所有在drivers属性中指定的JDBC驱动程序。这个过程由170至192行之间的代码实现。
创建连接池对象的任务由createPools()方法完成。该方法会创建所有属性名字的枚举对象,并搜索以“.url”结尾的属性。对于每个符合条件的属性,都会提取其连接池名字,然后创建连接池对象并将其保存在实例变量pools中。pools是一个散列表,实现了连接池名字到连接池对象的映射。
为了方便客户程序从指定连接池获取连接或返回连接,DBConnectionManager提供了getConnection()和freeConnection()方法。这些方法都要求在参数中指定连接池名字,具体的连接获取或返回操作则通过对应的连接池对象完成。它们的实现分别在特定代码块中详细展示。
当我们的客户程序发出调用release()的指令时,背后隐藏的引用计数机制开始发挥作用。当这个计数递减至零,意味着是时候释放所有数据库连接了。这时,各个连接池的release()方法被唤醒,它们协同工作,默默关闭所有活跃的连接。在这背后,有一个英勇的管理类release()方法,它的任务是撤销所有JDBC驱动程序的注册,确保系统资源的妥善管理。
现在,让我们通过一个Servlet使用连接池的生动示例来深入理解这一过程。想象一下,您是一位厨师,而Servlet API就像是您的烹饪手册。这本手册定义了Servlet的生命周期,就像菜谱中的制作步骤。
1. 创建并初始化Servlet,这就像是准备厨房和食材的过程(init()方法)。在这里,我们通过DBConnectionManager获取数据库连接的实例,并将其保存起来。
2. 响应客户程序的服务请求,就像开始烹饪的过程(service()方法)。我们调用getConnection()来获取数据库连接,执行各种数据库操作。完成任务后,我们通过freeConnection()将连接温柔地送回连接池,就像餐具被放回抽屉一样。
3. Servlet终止运行,释放所有资源,就像完成烹饪并清理厨房的过程(destroy()方法)。在这里,我们调用release()来关闭所有连接,确保没有资源被遗漏。然后,我们告别厨房,留给食客一个干净整洁的环境。
示例程序清单如下:
```java
import java.io.;
import java.sql.;
import javax.servlet.;
import javax.servlet.http.;
public class TestServlet extends HttpServlet {
private DBConnectionManager connMgr; // 我们的连接管理大厨
public void init(ServletConfig conf) throws ServletException { // 初始化和准备食材的步骤
superit(conf);
connMgr = DBConnectionManager.getInstance(); // 获取连接管理实例
}
public void service(HttpServletRequest req, HttpServletResponse res) throws IOException { // 开始烹饪的过程
res.setContentType("text/html"); // 设置响应类型
PrintWriter out = res.getWriter(); // 准备输出工具
Connection con = connMgr.getConnection("idb"); // 从连接池获取连接
if (con == null) { // 如果无法获取连接,告知食客无法提供服务并退出厨房
out.println("不能获取数据库连接.");
return;
}
// 执行数据库操作并处理结果的过程省略...(这里像是忙碌的厨师在炒菜)
connMgr.freeConnection("idb", con); // 完成烹饪后将餐具放回抽屉(连接池)中备用。
编程语言
- 用连接池提高Servlet访问数据库的效率(2)
- Angular.js实现注册系统的实例详解
- Vue项目中ESlint规范示例代码
- JS+CSS实现的经典tab选项卡效果代码
- mysql 5.7.14 安装配置简单教程
- 微信小程序绘制图片发送朋友圈
- AngularJs 利用百度地图API 定位当前位置 获取地址
- 详解如何在ASP.NET Core中编写高效的控制器
- es6+angular1.X+webpack 实现按路由功能打包项目的示例
- 跟我学习javascript的基本类型和引用类型
- PHP中header函数的用法及其注意事项详解
- nodejs中模块定义实例详解
- gliffy-confluence-plugin-9.1.2插件教程详解
- php实现xml转换数组的方法示例
- 微信公众平台开发之处理图片.Net代码解析
- php和redis实现秒杀活动的流程