管理Java servlet的数据库连接的最佳方法
-
04-07-2019 - |
题
在Java servlet中管理数据库连接的最佳方法是什么?
目前,我只是在 init()
函数中打开一个连接,然后在 destroy()
中关闭它。
但是,我担心“永久”保持数据库连接可能是件坏事。
这是处理此问题的正确方法吗?如果没有,有什么更好的选择?
编辑:进一步澄清一下:我尝试过为每个请求打开/关闭一个新连接,但是通过测试我发现由于创建了太多连接而导致性能问题。
在多个请求中共享连接有什么价值吗?对此应用程序的请求几乎都是“只读”的。而且来得相当快(虽然要求的数据相当小)。
解决方案
我实际上不同意使用Commons DBCP。您应该真的按照容器来管理连接池。
由于您正在使用Java Servlet,这意味着在Servlet容器中运行,并且我熟悉的所有主要Servlet容器都提供连接池管理(Java EE规范甚至可能需要它)。如果你的容器碰巧使用DBCP(就像Tomcat那样),那么,不管怎么说,只需使用容器提供的任何内容。
其他提示
正如大家所说,你需要使用连接池。为什么?怎么了?等
您的解决方案有什么问题
我知道这一点,因为我以前认为这是一个好主意。问题是双重的:
- 所有线程(servlet请求每个服务器都有一个线程)将共享同一个连接。因此,将一次处理一个请求。这非常慢,即使您只是坐在一个浏览器中并依靠F5键。尝试一下:这些东西听起来很高级,很抽象,但它是经验和可测试的。
- 如果连接因任何原因而中断,则不会再次调用init方法(因为servlet不会停止服务)。不要试图通过在doGet或doPost中放置一个try-catch来处理这个问题,因为那样你就会陷入困境(有点像编写app服务器而不被问到)。
- 与人们的想法相反,您不会遇到事务问题,因为事务开始与线程相关联而不仅仅是连接。我可能错了,但是因为这是一个糟糕的解决方案,所以不要冒汗。 醇>
- 建立真正的数据库连接成本很高。连接池总是有一些额外的连接,并为您提供其中一个。
- 如果连接失败,连接池将知道如何打开新连接
- 非常重要:每个线程都有自己的连接。这意味着线程应该在以下位置处理:在DB级别。 DB非常高效,可以轻松处理并发请求。
- 其他东西(比如集中JDBC连接字符串的位置等),但是这里有数百万篇文章,书籍等 醇>
为什么选择连接池
连接池为您提供了许多优势,但最重要的是它们解决了
的问题何时获取连接
在您的服务委托(doPost,doGet,doDisco,无论如何)中启动的调用堆栈中的某个地方,您应该获得连接,然后您应该做正确的事情并将其返回到finally块中。我应该提一下,C#主设计师dude曾经说过,你应该使用 finally
块比 catch
块多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变量,或者它将创建一个新连接并将其添加到池中。确保设置时间戳。完成连接后,只需将其返回到池中,池将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,结果 〜A
通常,您会发现每个请求的开放连接更易于管理。这意味着在servlet的doPost()或doGet()方法中。
在init()中打开它使所有请求都可用,并且当你有并发请求时会发生什么?