hibernate c3p0 连接无法释放 阻塞数据库操作
最近写的一个项目,发现每次启动tomcat进行几个数据库操作后就会卡住,重启tomcat又可以继续用,几个数据库操作后继续不可用。
在mysql中查询show processlist,发现这个项目的数据库有很多process在Sleep状态。
关闭tomcat,重启mysql,让数据库中的进程恢复0。
启动tomcat,这时候看到这个项目的数据库有5个连接,这是因为hibernate.cfg.xml里面配置了最小连接数是5
<property name="hibernate.c3p0.min_size">5</property>
用浏览器进行数据库操作,每进行一次数据库操作就会用一个新的mysql process。当进行到第6个操作的时候,没有重用前面已经存在的5个进程,而是新建了3个。当数据库操作超过20次的时候,这是就卡住了,因为hibernate.cfg.xml里面配置了最大连接数是20
<property name="hibernate.c3p0.max_size">20</property>
不知道为什么每次都会用新的进程,根据网上找到的一些解决办法,设置这个参数hibernate.connection.release_mode,这个参数有4个可选的value:
default,on_close,after_transaction
,after_statement
第一感觉就是应该用on_close, 但并没有起到作用,不知道是不是Spring的配置有什么问题
后来尝试了default和after_statement,只有after_statement可以起到作用
但是这里有个问题就是使用after_statement就破坏事务性,因为每个statement执行结束后都会释放连接,有多个操作的事务就不能保证事务性。
后来尝试了after_transaction,还好这个可以起到作用,至少比after_statement要好的多。我的transaction是写在DAO级别的,因为暂时还没有需要写在Service层的事务,根据以前项目的经验,transaction尽量写在有必要的地方,一个transaction执行尽量少的操作,以免阻塞其他线程。
至于default和on_close,据说default是等到达到最大连接数才去释放,没有验证。on_close为什么不释放也没有搞清楚,代码中是手动调用了sesson.close()的。
进一步的修改:之前sessionFactory是自己用Hibernate生成的,后来改成用Spring注入,似乎这个问题就没有了,另外sessionFactory.openSession()改成了getCurrentSession();
转载别人的:
四种释放连接的颗粒度,从粗到细:
- 采用第一种default配置,在spring中配置事务管理,由于事务颗粒度比较小,事务执行结束,也不会触发释放的操作,直至达到连接设置回收的最大超时时间才能回收连接,连接会迟迟不释放,导致连接池被占满。
- 采用第二种on_close, 同样在spring中配置事务,连接一直等到session 关闭时才会被释放,释放较慢,同样会导致连接池被沾满
- 采用after_transcation 的策略释放链接,每次事务都会释放链接。采用xml配置进行全局事务管理的配置,则不会出现连接池沾满的现象。但是如果采用注解,而某个持久层的 Dao类未标注Transactional注解,或者xml配置中遗漏了某个dao的事务管理配置,则该Dao操作执行结束,并不是一个事务的结束,不会释放链接,导致链接迟迟不能被释放,久而久之会导致连接池被占满。
- after_statement 的策略释放连接及时。 但也有一个弊端,由于每一次执行都会释放连接,如果一个事务需要几个执行操作,但第一次执行时连接就被释放,连接已归还给连接池了,第二次执行时获取新的连接,这样就无法保证事务性了。
- 上一篇: Vue---路由跳转和嵌套
- 下一篇: 全局变量、局部变量、静态变量和实例变量的区别