Spring+Hibernate做项目, 发现有member在不加事务的情况下就去调用 getSession() 方法, 结果导致数据库连接不能释放, 也无法正常的提交事务(只能做查询, 不能做save(), update()). 如果配合连接池使用的话, 不出几分钟就会导致连接池无法拿到新连接的情况.
不过, 只要给DAO或者Service加入了事务, 就不会出现连接泄漏的问题.
谈谈解决方案:
最佳方案: 加入事务, 例如 tx 标签或者 @Transactional 都可以.
最笨方案: 修改代码, 使用 HibernateTemplate 来完成相关操作:
但是缺陷显而易见, 要有N多的代码要进行改动.
HibernateDaoSupport 代码里面的原始说明文档指出直接调用getSession()方法必须用配套的releaseSession(Session session)来释放连接, 根据我的测试, 就算配置了 OpenSessionInViewFilter(前提: 不加事务), 也不会关闭这个Session. 也许有人说可以用连接池, 这种情况和Db pool没关系, 用了pool就会发现连接很快就会满, 只会over的更快. 反过来, 如果不配置OpenSessionInViewFilter, 在DAO里提前用 releaseSession()关闭连接, 就可能会在JSP中出现Lazy载入异常. 另一个不配事务的问题就是无法更新或者插入数据. 下面就是原始的JavaDoc中的说明:
不需要改原始代码的最终方案(方案三):
不过, 如果项目里已经有了大量直接调用getSession()而且没有加入事务配置的代码(如历史原因导致), 这些代码太多, 没法一一修改, 那就最好寻求其它方案, 最好是不需要修改原来的Java代码的方案. 我采用的这第三个方案是重写 HibernateDaoSupport用ThreadLocal保存Session列表并编写一个配套的过滤器来显式关闭Session, 并在关闭之前尝试提交事务. 下面是重写的 HibernateDaoSupport 代码:
用这个类来覆盖Spring内置的那个HibernateDaoSupport, 然后随便编写一个过滤器, 如下所示:
把这个过滤器配置在过滤器链的第一个, 就OK了.
最后也许会有人说, 为什么不用tx标签在Spring中来配置一个通配符就全部加入了事务了呢? 不过很遗憾, 经测试发现此方式无法实现跨DAO的Hibernate事务, 所以只好很无奈的放弃了这种方式.
配置事务管理:http://www.blogjava.net/robbie/archive/2009/04/05/264003.html
原帖:http://yhkyo.com/archives/196