我有一个主控制器 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”部分关闭连接(在下面的更新中解释了原因)。
“connection=null”适用于命令可能不需要打开数据库连接的情况,因为它正在寻找的数据缓存在身份映射中。
我试图 在.execute(tsk,connection);中将“Connection” obj 作为“null”参数传递;然后根据需要在对应的java类中打开连接
--> 它确实在命令中打开了连接,但是当进程返回到 servlet 时:“Connection”为空,因此没有关闭。
我该怎么做才能使“Connection” obj的值得到更新,以便在返回servlet时它不再是“Null”并且我可以关闭它?
我通常更喜欢使用打开/关闭数据库连接的控制器 servlet,那么处理这种情况的最佳方法是什么,您必须同时从池中执行某种“延迟加载”数据库连接时间保持分配给servlet的db连接
的打开/关闭?
更新(进一步解释):
- 说我有一个命令: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”内发生变化 - 如何将“globaly”更新为其新值,而不仅仅是在命令“X”的范围内“更新”?
解决方案
如果您遇到相同的情况,您可以选择以下两种解决方案:
您可以使用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 级别时,我可以:
- 关
- 回滚
- 犯罪
- ETC..
一切都在助手类的这个 hp 对象上。
我从中得到什么好处:
- 我将所有数据库打开/关闭/提交/回滚限制在一个地方,即负责执行命令的Servlet。
- 有3种情况:从不需要 db / 总是需要 db / 可能需要 db因此现在我将对数据库的调用减少1/3,知道数据库调用随着新功能和新用户注册呈指数增长,这非常重要。
它可能不是最干净的解决方法,但在这种方式和额外的“不必要的”1/3 数据库调用之间,它肯定更好。或者,如果您想要一个经过测试的、抽象的和干净的方法,则只需使用LazyConnectionDataSourceProxy 。