`
zzc1684
  • 浏览: 1223050 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

关于使用Spring导致c3p0数据库死锁问题

阅读更多

这个问题我实在是为整个 springsource 的员工蒙羞

如果大家使用 spring 控制事务,使用 Open Session In View 模式,


com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool-- timeout at awaitAvailable()


com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector -- APPARENT DEADLOCK!!!

 

还有诸如之类的若干 c3p0 报出的错误,对于流量稍大一点的网站,一般都会出现

 

当然,我确切的知道其原因是什么。


我只是想知道这个巨大的问题为什么这么多年过去了,仍旧在反复的不断地恼人的无解的一再发生。


我花了些时间google了一下,发现搜索
"com.mchange.v2.resourcepool.TimeoutException"  这个字符串,前5页都没有给出正确答案。

 

有一些解决方案,我称为workaround,并不是solution,例如
workaround1:
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --> 
<property name="acquireIncrement" value="5"/> 
workaround2:
是Spring中配置c3p0的时候,有一个配置属性是checkoutTimeout,把这个配置属性去掉就正常了。

 

好了,我来评价下这两种 workaround

第一种:这么搞下去,你的数据库连接数迟早会用光,到时结果是一样的,好比得了癌症这样做只是让你晚死几年。
第二种:很可笑,数据库死锁已经发生了,只不过牺牲掉等待的线程罢了,好比说有人在排队等饭吃,但永远等不到,你跟他说说别等了,直接自裁算了。算是很善良的做法,但是人终归是死了,换句话说,那个线程终归是未能给用户返回正确的request。

 

另外,还有很多兄弟将这类问题归咎于无辜的c3p0,例如这样的文章标题:
"谁来拯救C3P0的致命伤"

 

迄今为止,很少有人(我是没发现)了解,这个问题实际上是Spring的致命伤,我不清楚Spring的人晓不晓得这个问题,反正我google了一下springsource.org的网站,仅有两篇相关的论坛帖子,最终没有适当的回复。

 

两篇?!

 

如果说在座的各位曾经run过流量较大的网站,也用Spring做事务控制,我想有相当一部分都遇到这个问题,并且类似的问题在google上用英文问的人不计其数,有正确回答吗?没有,至少我没看到。

 

如何解释如此多人遇到此类问题,而spring的论坛上只有两篇相关的论坛帖子呢?
我不惮以最大的恶意来揣测SpringSource的诸位员工,即——被删了。

 

反正我已经以最大的恶意揣测过 Rod Johnson 和他的喽啰们了,不在乎多揣测一回。

 

因为,Spring知道,这是Spring的官方文档中的巨大问题,给无辜的用户们造成了巨大伤害,他们无法弥补,至少暂时使用Spring当前的架构,无法很轻松的弥补。

 

只要你用Spring控制事务,写了如下的事务控制配置:

<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager" ref="transactionManager"/>
        <property name="transactionAttributes">
                <props>
                        <prop key="save*">PROPAGATION_REQUIRED</prop>
                        <prop key="add*">PROPAGATION_REQUIRED</prop>
                        <prop key="set*">PROPAGATION_REQUIRED</prop>
                        <prop key="delete*">PROPAGATION_REQUIRED</prop>
                        <prop key="create*">PROPAGATION_REQUIRED</prop>
                        <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                        <prop key="*">PROPAGATION_REQUIRED</prop>
                </props>
        </property>
</bean>

或者

<tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
                <tx:method name="update*" propagation="REQUIRED" />
                <tx:method name="insert*" propagation="REQUIRED" />
                <tx:method name="save*" propagation="REQUIRED" />
                <tx:method name="delete*" propagation="REQUIRED" />
                <tx:method name="add*" propagation="REQUIRED" />
                <tx:method name="aud*" propagation="REQUIRED" />
                <tx:method name="get*" propagation="REQUIRED" read-only="true" />
                <tx:method name="find*" propagation="REQUIRED" read-only="true" />
        </tx:attributes>
</tx:advice>

 

那么,恭喜你,你成功掉进了Spring给你挖好的大坑,义无反顾的跳进去,还哭着喊着这是c3p0或者ORM框架(例如Hibernate)给你挖的坑,谁能救我?

 

答案是,没有人能救你,只有你自己
珍惜生命,远离Spring。

 

真正原因是什么,如何解决,我今天没空说了,要说的话,得画n张图,写n行示例代码告诉你为什么。

 

今天就简单给几个提示吧:
1、如果你不用spring,用jdbc,每次insert update delete 完了之后 commit 一下,问题就会不见。
2、好吧,我承认第一个提示是一种历史的倒退,那么你不用Spring,使用你用的ORM框架在每次 insert update delete 完了之后 commit 一下,问题也会不见。
3、好吧,我承认第二个提示也是一种历史的倒退,那么你不用Spring,用EJB3或者EJB3.1的@TransactionAttribute在你每个涉及修改数据库的方法上面标记一下,并且声明需要事务,问题也会不见。

 

总之,大家看到了,我都说了不要用Spring,如果有兄弟非要较真,我非要用Spring不可呢,没问题,我再给几个提示:

1、如果你用Spring来如上的粗放型控制事务,那么一定不敢用OpenSessionInView模式,如果你不用,然后在每个会导致数据库更新的方法上都标注Spring的@Transactional并且声明需要事务,问题也可能会不见。
2、如果你非要用OpenSessionInView模式,还要用Spring控制事务,那么对不起,无解。最好的结果是让人直接自杀,而不是等待吃饭一直等到饿死。

 

哑谜打到现在,有兄弟说了,我骂了Spring半天,不就是不能用OpenSessionInView模式吗?但,凡是个像样的牛牛写的web数据库访问指南,都说要用这个模式呢,和Spring有啥关系。

 

是的,你说对了一部分,请在Google上搜索一下“opensessioninviewfilter”这个字符串,返回280,000条结果,对吧。这个类是谁写的?是Spring写的。

 

再访问下这个链接:
http://www.google.cn/search?q=opensessioninviewfilter+site:springsource.org
有11300条结果,是spring的官网的搜索结果。

 

对不起,我今天实在没时间详细讲解这个filter与Spring事务控制无间配合之后的邪恶之处,我只能说,如果你用了,你基本上死定了。

 

这个模式没太大问题,但你必须精细的控制Transaction begin的时机,如果你在request上来不久就由于Spring的事务配置开始了一个事务,就基本上会导致死锁、连接池耗尽的一系列问题。

 

注意到了哈,我说基本上,嗯,这么用了,还有得救。如果你能够及时在每次更改数据库之后commit,并且在下一次更改之前重新start事务,就不会死锁。

 

但这么做,毫无疑问代码量会增大很多,可维护性会下降很多,不划算对吧。

 

是的,在filter里边 Open Session 或者 new 一个 EntityManager 没有错,

 

常见错误之一是没有在正确的时候开启事务,没有在正确的时候关闭事务,导致事务持续的时间无谓的过长。
常见错误之二是你如果用了ORM,那么就不应当写insert update delete语句,否则你会被迫无谓的在同一个request之内commit若干次,否则?死锁。

 

这个问题存在了若干年,已经成了一个传说,今天就先说到这里,有空再和大家详细解释问题的缘起、解决和展望。


P.S. 不用Spring也同样可能导致这个问题,那是另一码事了。本篇文章的主旨,是说我们被人卖了还帮人数钱的事情;而不是讨论我们被卖了到底怎么赎身(另文附上)。

分享到:
评论

相关推荐

    c3p0数据库连接池所需jar包

    1. 自动管理连接:C3P0会自动检测并关闭无效的连接,避免死锁问题。 2. 连接池大小动态调整:可以根据实际负载自动调整连接池的大小。 3. 空闲连接测试:定期对连接进行有效性检查,确保获取的连接都是可用的。 4. ...

    spring + c3p0 连接池

    本示例将深入探讨如何在Spring项目中配置并使用C3P0连接池,以实现高效、稳定的数据库连接管理。 **一、Spring框架简介** Spring是一个开源的Java平台,它简化了企业级应用的开发。Spring的核心特性包括依赖注入...

    C3P0连接池配置需要的jar包

    C3P0连接池是Java应用中常用的数据库连接池组件,它允许程序在不关闭物理连接的情况下,管理和重用数据库连接,从而提高了应用程序的性能和效率。C3P0库依赖于其他几个JAR包来实现其功能,包括`c3p0-0.9.2.1.jar`、`...

    c3p0-0.9.5.5.rar

    2. **自动检测与回收**:C3P0会定期检查连接的有效性,发现死锁或超时的连接会自动回收,确保应用使用的是健康状态的连接。 3. **连接池配置**:C3P0提供丰富的配置选项,如最小、最大连接数,测试连接的SQL语句,...

    c3p0压缩包

    由Maurice Priess创建并维护,c3p0因其轻量级、高效能和稳定性,被广泛应用于各种Java Web应用中,尤其是搭配Hibernate、Spring等框架进行数据库连接管理。 **二、主要功能** 1. **连接池管理**:c3p0能够管理...

    c3p0.jar文件

    2. **自动检测与修复**:c3p0可以定期检查连接的有效性,如果发现死锁或超时,会自动关闭并重新创建新的连接。 3. **连接池扩展性**:允许用户自定义连接创建、验证和销毁的策略,以适应不同的数据库环境。 4. **...

    SSM框架-c3p0架包zip

    在SSM框架中,C3P0的使用可能涉及到Spring的配置文件,通过`&lt;bean&gt;`标签定义C3P0数据源,并将其注入到需要使用数据库连接的组件中。 总之,C3P0是Java Web开发中一个重要的工具,它通过连接池技术提高了数据库操作...

    JavaEE C3P0简单案例

    这个案例将介绍如何在JavaEE项目中集成并使用C3P0,以实现数据库连接的高效管理。 首先,理解C3P0的核心功能。C3P0提供了数据库连接的池化,通过复用已存在的连接,避免了频繁创建和销毁连接带来的开销。它还提供了...

    c3p0-0.9.5.5打包.rar

    此外,c3p0还提供了自动检测死锁、空闲连接回收、连接超时等多种特性,确保了数据库连接的稳定性和效率。 3. **c3p0-oracle-thin-extras-0.9.5.5.jar**: 这个JAR文件是针对Oracle数据库的特定扩展,它提供了对...

    c3p0-0.9.2-pre1.rar

    1. **自动管理连接**: c3p0能自动检测并修复数据库连接,如检测到死锁或空闲过久的连接,会自动进行关闭和重新创建。 2. **连接测试**: 可以在获取连接时或在连接归还到池时进行健康检查,确保返回给应用的都是有效...

    c3p0数据池jar包完整版

    在数据库连接池中,C3P0提供了许多高级特性,如自动检测死锁、自动调整连接池大小、空闲连接测试以及连接池的监控等。这些功能使得C3P0成为许多企业级Java应用的首选连接池组件。 1. **配置与初始化**: 使用C3P0...

    c3p0连接池的使用

    如果项目使用Spring框架,可以将C3P0配置为Spring的数据源,这样可以在Spring的管理下实现自动初始化和销毁。在`applicationContext.xml`中配置C3P0数据源,并在需要的地方通过@Autowired注解注入。 ```xml &lt;!-- ...

    JDBC连接池jar包__C3P0.zip

    2. **配置C3P0**:在Java代码中创建C3P0数据源实例,通常在Spring框架中,会通过XML配置文件或Java配置类来设置C3P0的相关参数,例如最大连接数、最小连接数、初始化连接数、空闲超时时间等。 ```xml ...

    jdbc数据库连接池工程文件_e3p0

    除了`e3p0`,还有其他著名的数据库连接池实现,如`C3P0`、`HikariCP`和`Apache DBCP2`等。它们各有特点,开发者可以根据项目的具体需求选择合适的连接池实现。 总的来说,`JDBC数据库连接池`是Java开发中不可或缺的...

    连接数据库的相关jar包

    同样,使用C3P0也需要进行相应的配置,包括数据库驱动类、连接池大小和超时设置等。 3. 其他数据库连接相关的JAR包:除了DBCP和C3P0,还有其他一些常用的JAR包用于数据库连接,如: - JDBC驱动:每个数据库供应商...

    JDBC数据源连接池的配置和使用示例

    - C3P0:开源的JDBC连接池,提供了比JDBC更强大的功能,如自动检测死锁、自动重连等。 - DBCP:Apache的一个开源项目,基于Jakarta-pool实现,是Tomcat默认的数据源。 - HikariCP:被誉为“最快的Java JDBC连接池”...

    JAVA数据库驱动大全(jar)

    为了提高性能和资源利用率,开发中通常会使用数据库连接池,如C3P0、HikariCP、Druid等,它们预先创建一定数量的连接,供多个线程复用,避免了频繁的数据库连接创建和释放。 6. JDBC的最佳实践: - 使用...

    java 中连接数据库语句和模块

    因此,使用连接池(如C3P0、HikariCP或Apache DBCP)可以高效地管理和重用数据库连接。连接池提供初始化、获取和释放连接的方法,提高了系统效率。 7. **事务管理**:在Java中,`Connection`对象提供了开始、提交和...

    数据库连接池在web开发中的应用

    C3P0提供了许多高级特性,如自动检测死锁、连接测试等,同时支持JDBC 3.0和4.0规范。然而,C3P0的性能也受到一些批评,尤其是在高并发环境下。 **HikariCP** HikariCP由Brett Wooldridge开发,被誉为最快的Java...

    Java笔试题汇总(包括Java基础框架数据库等,大部分公司招聘使用的)

    - **数据库连接池**:如C3P0、Druid、HikariCP,理解其作用和配置。 4. **其他** - **多线程**:线程的创建、同步、通信,以及死锁问题的预防和解决。 - **网络编程**:Socket编程,TCP/IP协议栈,HTTP协议。 -...

Global site tag (gtag.js) - Google Analytics