我有一个主控制器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”适用于命令可能不需要打开数据库连接的情况,因为它所寻找的数据缓存在identity map中。
我试图在 .execute(tsk,connection); 中将“Connection” obj作为“null”参数传递,然后在相应的java类中传递给打开连接如果需要
- >它确实打开了命令中的连接,但是当进程返回到servlet时:“Connection”为空,因为没有关闭。
我该怎么做才能使“连接” obj的值得到更新,以便当回到servlet中时它不再是“空”并且我能够关闭它?
我通常更喜欢使用打开/关闭数据库连接的控制器servlet,那么处理这种情况的最佳方法是你必须做某种“延迟加载”来自池的数据库连接,同时保持分配给servlet的数据库连接的打开/关闭?
更新(进一步解释):
我想拥有的系统是:
(1)“客户请求”
(2)---> “Servlet”: command.execute(连接)//其中connection = null for now
(3)---> “命令X”:我是否需要进入数据库或记录在身份图中?
(3.a)需要进入数据库的情况:
(3.a.1)connection = datasource.getconnection
(3.a.2)去获取数据
(4)---> 返回到servlet:关闭“Servlet”中的“连接”
现在它一直工作到(3.a.2),但是一旦回到(4),似乎连接仍然是“空”,因此代码:
finally {
if(connection!=null)
connection.close()
}
不起作用(不关闭连接)因此数据库池会像这样耗尽。 连接 - 以“null”开头并在命令“X”内更改 - 如何将“globaly”更新为其新值,而不仅仅在命令“X”范围内“更新”?
将(S)
如果您遇到相同的情况,您可以选择这些 2解决方案:
您可以使用LazyConnectionDataSourceProxy,如@Ryan Stewart所提及的“干净抽象”和更专业的解决方案
或者如果你想使用下面描述的解决方案(基本上我实现了类似于“LazyConnectionDataSourceProxy”的类,但它不是那么干净,它的细节抽象少于“LazyConnectionDataSourceProxy”)
我的个人解决方案,详情:
这是我在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对象。
我从中获得了什么好处:
它可能不是最干净的解决方法,但是在这种方式和额外的“不必要的”1/3数据库调用之间,肯定会更好。或者如果你想要一个经过测试,抽象和干净的方法,只需使用LazyConnectionDataSourceProxy。
答案 0 :(得分:2)
使用LazyConnectionDataSourceProxy
。然后每次只获得一个“连接”,但只有在您实际执行需要的连接时才会打开真正的连接。因此,你遵守Hiro2k指出的“创建/破坏”智慧,因为连接的生命周期完全由你的servlet管理。
答案 1 :(得分:0)
在您的具体情况下,唯一的方法是返回连接。 Java没有任何可以帮助您的引用语义传递,不像C,您可以传入对连接的引用,然后在方法中设置它。
我不建议你的方法返回连接,而是记住这个简单的规则,一切都会按预期工作:
创建它的对象负责销毁它。
如果您想要做的是不为不需要的命令实例化连接,那么在命令界面中添加一个方法,只需要一个方法返回。
Command command = cmdFactory.getInstance().getCommand(Cmd);
if(command.requiresConnections){
connection = getConnection();
}
command.execute(tsk,connection);