在Java servlet中管理数据库连接的最佳方法是什么?
目前,我只是在init()
函数中打开一个连接,然后将其关闭destroy()
.
但是,我担心"永久"保持数据库连接可能是一件坏事.
这是处理这个问题的正确方法吗?如果没有,有什么更好的选择?
编辑:进一步澄清:我已经尝试过为每个请求打开/关闭一个新连接,但是通过测试我看到由于创建了太多连接而导致的性能问题.
在多个请求上共享连接有什么价值吗?对此应用程序的请求几乎都是"只读"并且相当快(尽管请求的数据相当小).
正如大家所说,你需要使用连接池.为什么?怎么了?等等.
你的解决方案有什么不对
我知道这一点,因为我曾经认为这是一个好主意.问题是双重的:
所有线程(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.您应该真的按照容器来管理连接池.
由于您正在使用Java Servlet,这意味着在Servlet容器中运行,并且我熟悉的所有主要Servlet容器都提供连接池管理(Java EE规范甚至可能需要它).如果你的容器碰巧使用DBCP(就像Tomcat那样),那么,好吧,只要使用你的容器提供的任何东西.