Java &引用;“延迟初始化”;来自jndi数据源/连接池的jdbc连接:可行性

Java &引用;“延迟初始化”;来自jndi数据源/连接池的jdbc连接:可行性,java,servlets,jdbc,jndi,connection-pooling,Java,Servlets,Jdbc,Jndi,Connection Pooling,我有一个主控制器servlet,在其中我实例化了一个数据源。servlet打开和关闭连接。servlet主要使用“工厂模式”实例化来自应用程序的命令。下面是一些代码来解释: public void init() throws ServletException { super.init(); try { datasource =(DataSource) getServletContext().getAttribute("DBCPool"); }

我有一个主控制器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”用于命令可能不需要打开db连接的情况,因为它要查找的数据缓存在数据库中。

我试图在.execute(tsk,Connection)中将“Connection”obj作为“null”参数传递;然后在相应的java类中打开连接(如果需要)

-->它确实在命令中打开了连接,但是当进程返回到servlet时:“连接”为null,因此没有关闭
如何更新“Connection”obj的值,使其在返回servlet时不再为“Null”,并且可以关闭它?

我通常更喜欢使用打开/关闭db连接的控制器servlet,那么,在这种情况下,您必须执行某种“延迟加载”池中的db连接,同时保持分配给servlet的db连接的打开/关闭,处理这种情况的最佳方法是什么?

更新(进一步解释):

  • 假设我有一个命令:X.java
  • 此命令可能/可能不需要db连接(取决于搜索的数据是否在标识映射中)
我想要的系统是:

(1) “客户请求”

(2) -->“Servlet”:command.execute(connection)//where connection=null当前

(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”的范围内“updated”

解决方案

如果遇到相同的情况,您可以选择以下两种解决方案:

  • 您可以使用@Ryan Stewart提到的“干净抽象”和更专业的解决方案

  • 或者,如果您想使用下面描述的解决方案(基本上,我实现了一个类似于“LazyConnectionDataSourceProxy”的类,但它没有“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”中说,需要一个db连接,我这样做:

Connection connection = hp.LazyGet();//Now got a connection from the pool
这样,当流程流回到servlet级别时,我可以:

  • 接近
  • 回滚
  • 承诺
  • 等等
所有这些都在helper类的hp对象上。

我从中得到了什么好处:

  • 我将所有数据库的打开/关闭/提交/回滚限制在一个地方,即负责执行命令的Servlet
  • 有3种情况:从不需要db/总是需要db/可能需要db,因此现在我将对数据库的调用减少了1/3,这是非常清楚的,数据库调用随着新特性和新用户注册呈指数增长

这可能不是最干净的解决方法,但在这种方式和使用额外的“不必要的”1/3数据库调用之间,它肯定更好。或者,如果您想要一个经过测试的、抽象的、干净的方法,就使用它。

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

我不建议您使用返回连接的方法,请记住这条简单的规则,一切都将按照您的预期进行:

创建它的对象负责销毁它

如果您不想为不需要连接的命令实例化连接,那么可以向您的命令接口添加一个方法,该方法只在需要时返回

Command command = cmdFactory.getInstance().getCommand(Cmd);
if(command.requiresConnections){
     connection = getConnection();
}
command.execute(tsk,connection);

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

thx获取提示。我无法返回连接,因为每个命令都返回要发送到客户端的数据。至于“创建它的对象负责销毁它”,这是非常正确的,但这意味着我必须在每个命令中打开/关闭连接。我试图看看是否有可能只在一个地方保持打开/关闭的方式,即servlet。如果看起来绝对没有办法,那么我会按照你说的去做。再次感谢,但我想你误解了我的问题,你写的东西是我代码中已经有的东西。现在的代码“总是”打开一个连接,我想知道的是,当一个命令可能需要/可能不需要连接时,您怎么做