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

时间:2012-04-20 04:44:50

标签: java servlets jdbc jndi connection-pooling

我有一个主控制器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的数据库连接的打开/关闭

更新(进一步解释):

  • 说我有一个命令: X.java
  • 此命令可能/可能不需要数据库连接(取决于搜索的数据是否在身份映射中)

我想拥有的系统是:

(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”)

我的个人解决方案,详情:

  • 我创建了一个“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对象。

我从中获得了什么好处:

  • 我限制一个位置的所有数据库 open / close / commit / rollback ,即负责执行命令的Servlet。
  • 3 的情况:永远不需要db /总是需要db /可能需要db 因此现在我减少了对 1/3 ,这是非常了解数据库调用随着新功能和新用户注册而呈指数级增长。

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

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

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

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

  

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

如果您想要做的是不为不需要的命令实例化连接,那么在命令界面中添加一个方法,只需要一个方法返回。

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