管理Java servlet的数据库连接的最佳方法

在Java servlet中管理数据库连接的最佳方法是什么?

目前,我只是在init()函数中打开一个连接,然后在destroy()关闭它。

但是,我担心“永久”持有数据库连接可能是一件坏事。

这是处理这个问题的正确方法吗? 如果没有,有什么更好的选择?

编辑:进一步澄清:我已经尝试过为每个请求打开/关闭一个新连接,但是通过测试我看到由于创建了太多连接而导致的性能问题。

在多个请求上共享连接有什么价值吗? 对这个应用程序的请求几乎都是“只读”并且相当快(尽管请求的数据相当小)。

我实际上不同意使用Commons DBCP。 您应该真的按照容器来管理连接池。

由于您正在使用Java Servlet,这意味着在Servlet容器中运行,并且我熟悉的所有主要Servlet容器都提供连接池管理(Java EE规范甚至可能需要它)。 如果你的容器碰巧使用DBCP(就像Tomcat那样),那么,好吧,只要使用容器提供的任何东西。

正如大家所说,你需要使用连接池。 为什么? 怎么了? 等等。

你的解决方案有什么不对

我知道这一点,因为我曾经认为这是一个好主意。 问题是双重的:

  1. 所有线程(servlet请求每个服务器都有一个线程)将共享同一个连接。 因此,将一次处理一个请求。 这非常慢,即使您只是坐在一个浏览器中并依靠F5键。 尝试一下:这个东西听起来很高级和抽象,但它是经验和可测试的。
  2. 如果连接因任何原因而中断,则不会再次调用init方法(因为servlet不会停止服务)。 不要试图通过在doGet或doPost中放置try-catch来处理这个问题,因为那样你就会陷入困境(有点编写app服务器而不被问到)。
  3. 与人们的想法相反,您不会遇到事务问题,因为事务开始与线程相关联而不仅仅是连接。 我可能错了,但是因为这是一个糟糕的解决方案,所以不要出汗。

为何选择连接池

连接池为您提供了许多优势,但最重要的是它们解决了问题

  1. 建立真正的数据库连接是昂贵的。 连接池总是有一些额外的连接,并为您提供其中一个。
  2. 如果连接失败,则连接池知道如何打开新连接
  3. 非常重要:每个线程都有自己的连接。 这意味着线程在应该处理的位置处理:在DB级别。 DB非常高效,可以轻松处理并发请求。
  4. 其他的东西(如集中JDBC连接字符串的位置等),但有数百万篇文章,书籍等

何时获取连接

在您的服务委托(doPost,doGet,doDisco,等等)中启动的调用堆栈中的某个位置,您应该获得连接,然后您应该做正确的事情并将其返回到finally块中。 我应该提一下,C#主建筑师dude曾经说过,你应该使用finally块比块块多100倍。 真正的话从未说过……

哪个连接池

您在servlet中,因此您应该使用容器提供的连接池。 除了获得连接的方式之外,您的JNDI代码将完全正常。 据我所知,所有servlet容器都有连接池。

以上答案的一些评论建议使用特定的连接池API。 您的WAR应该是可移植的并且“只是部署”。 我认为这基本上是错误的。 如果您使用容器提供的连接池,那么您的应用程序将可以部署在跨多台计算机的容器上,以及Java EE规范提供的所有内容。 是的,必须编写特定于容器的部署描述符,但这是EE方式,mon。

一位评论者提到某些容器提供的连接池不能与JDBC驱动程序一起使用(他/她提到了Websphere)。 这听起来完全是牵强附会和荒谬的,所以它可能是真的。 当这样的事情发生时,把你应该做的所有东西都丢在垃圾里,尽你所能。 这就是我们得到的报酬,有时:)

我使用Commons DBCP 。 这是一个Apache项目,可以为您管理连接池。

您只需在doGet中获取连接,或者doPost运行查询,然后在finally块中关闭连接。 (con.close()只是将它返回到池中,它实际上并没有关闭它)。

DBCP可以管理连接超时并从中恢复。 如果您的数据库在任何时间段内出现故障,您当前正在做的事情,您将不得不重新启动您的应用程序。

你在联网吗? 如果没有,您可能应该减少打开和关闭连接的开销。

一旦完成,只要按照需要保持连接打开,正如John建议的那样。

最好的方法是,我正在通过Google查找更好的参考表,就是使用池。

在初始化时,您将创建一个池,其中包含数据库的X个SQL连接对象。 将这些对象存储在某种List中,例如ArrayList。 这些对象中的每一个都有一个’isLeased’的私有布尔值,上次使用的时间很长,还有一个Connection。 无论何时需要连接,都可以从池中请求连接。 池将为您提供第一个可用连接,检查isLeased变量,或者它将创建一个新连接并将其添加到池中。 确保设置时间戳。 完成连接后,只需将其返回到池,将池设置为false。

为了避免不断地连接数据库,您可以创建一个工作线程,该线程偶尔会通过池并查看上次使用连接的时间。 如果它足够长,它可以关闭该连接并将其从池中删除。

使用它的好处是,您没有等待连接对象连接到数据库的漫长等待时间。 您已建立的连接可以根据需要重复使用。 并且您将能够根据您认为应用程序的繁忙程度来设置连接数。

您应该只在需要时保持数据库连接打开,这取决于您正在执行的操作可能属于doGet/doPost方法的范围。

汇集它。

此外,如果您正在使用原始JDBC,您可以查看一些可以帮助您管理Connection,PreparedStatement等的内容。除非您有非常严格的“轻量级”要求,例如,使用Spring的JDBC支持将简化您的代码很多 – 你不会被迫使用Spring的任何其他部分。

在这里看一些例子:

http://static.springframework.org/spring/docs/2.5.x/reference/jdbc.html

与数据源关联的连接池应该可以解决问题。 您可以在servlet请求方法( doget / dopost等)中获取dataSource的连接。

dbcp,c3p0和许多其他连接池可以满足您的需求。 在汇集连接时,您可能希望汇总语句和PreparedStatements; 此外,如果您指的是READ HEAVY环境,您可能希望使用ehcache之类的东西来缓存一些结果。

BR,
〜一

通常,您会发现每个请求的打开连接更容易管理。 这意味着在servlet的doPost()或doGet()方法中。

在init()中打开它使它可用于所有请求以及当您有并发请求时会发生什么?