在HttpSession中存储JDBC连接

7
我最近接手了一些代码,在其中发现一个JDBC连接在过滤器中被初始化,并添加到每个用户的HttpSession中。然后该连接在用户的Web应用程序的各个部分中被重复使用。这立即引起了我的注意,因为它是一种代码异味。我想回到编写此代码的开发人员那里,并解释他不应该这样做的原因...但也许我自己也不太确定...
除了占用不必要的内存空间和可能限制数据库可用连接数之外,还有其他原因会导致您不希望将JDBC连接存储在会话中吗?

也许你应该先向我们解释一下为什么你认为他不应该这样做? - Thorbjørn Ravn Andersen
@Thorbjørn 我猜我的初始反应是因为我以前从未见过这种情况。但是为1000个用户创建1000个JDBC连接似乎很愚蠢... - jconlin
每个连接是否有特殊之处,还是可以轻松地进行汇集? - Thorbjørn Ravn Andersen
如果您的唯一关注点是性能,请使用连接池。我在您的问题历史记录中看到您熟悉Tomcat,这里是如何操作的链接:http://tomcat.apache.org/tomcat-6.0-doc/jndi-resources-howto.html - BalusC
@BalusC - 我对连接池非常熟悉,因为我通常使用它,或者让ORM库来处理。但我从未见过这种情况。不过还是谢谢你提供的信息! - jconlin
4个回答

7

您已经提到了显而易见的问题,一个用户对应一个数据库连接是不可扩展的。您的用户应该与访问数据模型完全解耦。这里有几个问题需要注意:

  • 如果连接变得陈旧,会发生什么?那个用户将无法使用数据库连接进行任何有用的操作,因此他们可能不得不退出登录并重新登录以获得新的连接。真是糟糕。
  • JDBC连接不是线程安全的。如果用户决定同时运行几个任务,那么情况就会非常混乱。

线程安全问题和过期连接确实是一个不错的观点。我想我只是想知道这到底有多糟糕的做法。 - jconlin

4
将JDBC连接保持在HttpSession中甚至在Servlet层访问连接的整个想法并不太合理。更明智的做法是在应用服务器上池化连接,从而减少打开连接的数量。同一应用程序能够以更好的性能为更多同时用户提供服务。
在大型应用程序中,不太可能所有请求都会命中数据库,因为相同的信息很可能已经在缓存中找到了。
在集群环境中,对于非粘性会话,如果请求命中创建会话的另一个盒子,则JDBC连接甚至无效。
通常,您应该仅在会话中存储特定于用户的信息,即使如此也要将所需的会话量减少到最小。会话中的更多数据意味着在集群中复制会话时需要在应用程序服务器之间传输更多数据(如果会话未存储在中央DB或缓存中)。

3
尽管我无从得知,但是我猜测你的同事最初可能采用了与初学者和演示程序相同的方式,即每个请求都会从管理器中获取一个新连接,他很快发现这会严重降低请求速度,因此现在他通过将连接“池化”在用户会话中来避免创建连接。这解决了在连接的第二次及之后请求时对性能造成的问题,但这是一种非常笨拙而且不可扩展的解决方案。如果您的应用程序用户基数增长,具有打开会话的用户数量将很快超过数据库可以提供的最大连接数,那么就有会话或数据库连接超时的问题...“行业标准”的解决方案是使用连接池。现代版本的Tomcat已经内置了连接池,其他Web应用服务器也是如此。如果没有,您可以轻松安装自己的连接池。这使您可以完全独立地管理一组连接,而不受用户会话的影响。另一个连接池的好处是,一旦池“预热”(即有多个连接正在使用并初始化),甚至“首次用户会话请求”也能够快速获得连接,因此整体吞吐量将优于当前情况。

2

为什么不应该在会话中存储JDBC连接:

  • 会话和连接超时可能会导致问题
  • 无法独立扩展连接与会话
  • 线程安全性
  • 会话复制将无法正常工作 - 引入不必要的状态
  • 没有良好的黏合/内聚设计 - 不解耦不同的关注点是不良架构。

连接池可以帮助解决1到3个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接