2

我有一个主控制器 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 。

4

2 回答 2

2

使用LazyConnectionDataSourceProxy. 然后每次都获得一个“连接”,但只有在您实际执行需要的操作时才会打开真正的连接。因此,您遵循 Hiro2k 指出的“创建/销毁”智慧,因为连接的生命周期完全由您的 servlet 管理。

于 2012-04-20T22:26:43.103 回答
0

在您的特定情况下,唯一的方法是返回连接。Java 没有任何可以帮助您的引用传递语义,这与 C 不同,您可以将引用传递给连接,然后在方法中设置它。

我不建议您的方法返回连接,而是记住这个简单的规则,一切都会按您的预期工作:

创建它的对象负责销毁它。

如果您想要做的不是为不需要的命令实例化连接,则向您的命令接口添加一个方法,该方法在需要时简单地返回。

Command command = cmdFactory.getInstance().getCommand(Cmd);
if(command.requiresConnections){
     connection = getConnection();
}
command.execute(tsk,connection);
于 2012-04-20T04:51:34.283 回答