【发布时间】:2012-05-01 16:40:33
【问题描述】:
我有一个主控制器 servlet,我在其中实例化了一个 数据源。 servlet 打开和关闭连接。主要是,servlet 使用“工厂模式”实例化来自应用程序的命令。这里有一些代码来解释:
public void init() throws ServletException {
super.init();
try {
datasource =(DataSource) getServletContext().getAttribute("DBCPool");
}
catch (Exception e) {
}
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//some code...
Connection connection = null;
if(cmd.mightNeedLazyLoadingAConnection)
{
connection = null;
}
else
connection = getConnection();//where getConnection is a method: datasource.getconnection();
//now a command (a java class) is instantied, to which the "null" CONNECTION obj is passed as parameter
cmdFactory.getInstance().getCommand(Cmd).execute(tsk,connection);
//some code
//Then wherever there is catch exception i close() the connection
// and it is always closed in finally
finally {
if(connection!=null)
connection.close()
}
}
现在,对于第一种情况,即connection=null,这有一个问题,因为它永远不会关闭“finally”中的连接 b> 部分(在下面的 Update 中解释了原因)。
"connection=null" 适用于命令可能不需要打开数据库连接的情况,因为它正在寻找的数据缓存在 identity map 中。
我尝试在 .execute(tsk,connection); 中将 "Connection" obj 作为“null”参数传递,然后在相应的 java 类中打开一个连接如果需要
--> 它确实在命令中打开了连接,但是当进程返回到 servlet 时:“Connection”为空,因此未关闭。
我该怎么做才能使 "Connection" obj 的值得到更新,以便在返回 servlet 时它不再是“Null”并且我可以关闭它?
我通常更喜欢使用 打开/关闭 db 连接的控制器 servlet,那么处理这种必须执行某种“延迟加载”的场景的最佳方法是什么来自池的 db 连接,同时保持分配给 servlet 的 db 连接的 opens/close?
更新(进一步解释):
- 说我有一个命令:X.java
- 此命令可能/可能不需要数据库连接(取决于搜索的数据是否在身份映射中)
我想要的系统是:
(1)“客户请求”
(2)---> "Servlet": command.execute(connection) //where connection = null for now
(3) ---> “Command X”:我需要去数据库还是记录在身份映射中?
(3.a) 需要去数据库的情况:
(3.a.1)connection = datasource.getconnection
(3.a.2) 去获取数据
(4)--->返回到servlet:关闭“Servlet”中的“连接”
现在它一直工作到 (3.a.2),但一旦回到 (4),连接似乎仍然是“null”,因此代码:
finally {
if(connection!=null)
connection.close()
}
不起作用(不关闭连接),因此数据库池会像那样被耗尽。 连接(以“null”开头并在命令“X”内发生变化)如何将“全局”更新为其新值,而不仅仅是在命令“X”范围内“更新”?
解决方案
如果您遇到相同的情况,您可以选择以下 2 种解决方案:
您可以使用 LazyConnectionDataSourceProxy,正如 @Ryan Stewart 所提到的“干净的抽象”和更专业的解决方案
-
或者,如果您想使用下面描述的我的解决方案(基本上我实现了一个类似于“LazyConnectionDataSourceProxy”的类,但它不是那么干净,它比“LazyConnectionDataSourceProxy”具有更少的细节抽象)
我的个人解决方案,详情:
- 我创建了一个“Helper”类,它的构造函数将“datasource”作为参数
- 此帮助程序类具有以下方法:“延迟获取”连接池、“关闭”连接
- 这个类在 servlet 中实例化,它仅在整个应用程序需要时从池中获取连接。
这是我在 servlet 中添加/修改的代码:
Connection connection = null;
if(cmd.mightNeedLazyLoadingAConnection)
{
helper hp = new helper(datasource);
cmdFactory.getInstance().getCommand(Cmd).execute(tsk,hp);
}
else
{
connection = getConnection();
cmdFactory.getInstance().getCommand(Cmd).execute(tsk,connection);
}
然后在命令“X”中说,我需要一个数据库连接:
Connection connection = hp.LazyGet();//Now got a connection from the pool
这样,当进程流回到servlet级别时,我可以:
- 关闭
- 回滚
- 提交
- 等等..
所有在帮助类的这个 hp 对象上。
我能从中得到什么好处:
- 我将所有数据库打开/关闭/提交/回滚限制在一个的地方,即负责执行命令的Servlet。
- 有 3 个案例:从不需要 db / 总是需要 db / 可能需要 db 因此现在我减少了对数据库的调用 1/3 ,知道数据库调用随着新功能和新用户注册而呈指数增长,这非常重要。
这可能不是 最干净的 解决方法,但在这种方式和额外的“不必要的”1/3 数据库调用之间,它肯定更好。或者,如果您想要一个经过测试、抽象且干净的方法,请使用LazyConnectionDataSourceProxy。
【问题讨论】:
标签: java servlets jdbc jndi connection-pooling