数据库连接池死锁的原因和处理方法

数据库连接池是java软件常用的组件,但对数据库连接池不正确的使用会造成软件的死锁。
死锁的产生原理是:存在线程同时占有两个以上的连接对象的情况。

比如某连接池中有2个连接对象。
有两个线程分别占用了一个,又分别来申请另一个。这时由于连接池空,而两个线程本身都卡在连接池上,不可能释放原来占有的连接对象,这时产生死锁。

连接池死锁,会导致软件和数据库相关的部份无响应。比如登陆功能,会用数据库做用户校验,发生连接池死锁后,登陆功能会无法使用(点登陆按钮后,长时间无相应)。

连接池死锁的问题可以参看以下文章:

http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jspopic=%2Frzatz%2F51%2Fprogram%2Fdatapool.htm

解决方法:一个线程中同时只允许使用一个连接对象。

一段数据库逻辑通常只需要一个连接对象,因此在一个方法中实现这点是比较容易的。但是当发生如下情形时则比较麻烦:
有两个方法A和B,A和B都要使用数据库连接,而A在事务中调用了B。

为了解决这个问题有如下两种办法:

一是,将连接对象放在线程的ThreadLocal中。这样A和B即可共享连接对象了。但这种方法需要考虑嵌套事务的问题。数据库是不允许嵌套事务的。因此,要么避免嵌套事务,要么自动合并事务。
注意:采用传参的形式也可以做到这点,但只能就问题解决问题,不是框架层面的解决方案,也要处理嵌套事务的问题。

二是,直接人为在代码上保证一个线程不同时占有两个连接对象。幸好这样的情况从经验上看并不多,只要找到这样的方法,想办法拆分一下逻辑,将调用的部份从事务中拿出来即可。

     还有一种古怪的办法,就是新起一个线程来调用B。如果A对B的返回值有依赖关系,这种办法是行不通的,不推荐使用。

    有人认为只要给连接池设置一个超时就行了。可是,这样做并不恰当。因为,连接是应该可以共享的,如果暂时,连接池内没有连接可用,应该让申请者等待可用的连接,而不是抛出超时异常,这样会导致申请者整个过程的失败。

 

 

2012-02-02

 

新发现了一种由连接池引起的死锁情况,并不是由一个线程占用两个以上的连接引起的,是因为线程取得连接后被锁卡住不能归还引起的方式如下:

 

连接池中有一个连接对象。

 

A线程:

取得连接对象

开始事务

synchronized(cache){

    数据库代码

}

提交

关连接

 

B线程:

synchronized(cache){

   取得连接,操作数据库。

}

 

A线程执行卡在同步块外,此时连接池为空。

B线程进入同步块,在取得连接时卡在连接池上。

 

 

 

 

来源:iteye_12828

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2010年9月10日
下一篇 2010年9月10日

相关推荐