Java EE+Hibernate 5出现Transaction already active异常如何解决?
异常触发原因
报错java.lang.IllegalStateException: Transaction already active的核心触发逻辑是:你在Hibernate会话已经绑定了活跃事务的前提下,重复调用了事务的begin()方法。结合你提供的代码,具体原因分为三类:
- 你使用的
sessionFactory.getCurrentSession()会将会话绑定到当前线程,若上层业务代码已经开启过事务且未提交/回滚,DAO层拿到的就是带有活跃事务的会话,此时再调用tx.begin()直接触发报错。 - 你当前的DAO方法异常捕获逻辑不完整,如果之前调用该方法时抛出了异常,事务没有被回滚,就会导致当前线程一直持有带活跃事务的会话,后续再调用同个DAO方法时就会报错。
- 单条查询操作本身不需要显式开启事务,你在DAO层为单个查询强行做事务管理的写法本身就不合理,很容易出现事务边界冲突。
修复方案
方案1:快速修复,新增事务状态判断
修改DAO方法,开启事务前先判断当前是否有活跃事务,同时补充异常场景的事务回滚逻辑,避免事务残留:
@Override public Pic getById(Integer id) throws BDException { Session session = sessionFactory.getCurrentSession(); Transaction tx = session.getTransaction(); boolean isNewTx = false; try { // 仅无活跃事务时才开启新事务 if (!tx.isActive()) { tx.begin(); isNewTx = true; } Pic p = (Pic) session.get(myClass, id); // 仅本方法开启的事务,才由本方法提交 if (isNewTx) { tx.commit(); } return p; } catch(Exception e) { // 异常场景如果事务活跃,直接回滚避免残留 if (tx.isActive()) { tx.rollback(); } throw new BDException("数据查询失败", e); } }
方案2:调整事务边界到业务层(推荐)
DAO层仅负责实现数据操作逻辑,事务统一放到业务层管理,既避免事务边界冲突,也支持多个DAO操作合并到同一个事务里执行:
- 简化DAO层逻辑,去掉事务管理代码:
@Override public Pic getById(Integer id) throws BDException { Session session = sessionFactory.getCurrentSession(); try { return (Pic) session.get(myClass, id); } catch(Exception e) { throw new BDException("数据查询失败", e); } }
- 业务层统一管理事务:
// 业务层调用示例 Transaction tx = null; try { tx = sessionFactory.getCurrentSession().beginTransaction(); Pic p = picDAO.getById(1000); // 其他业务逻辑、其他DAO操作均可放在同一个事务里 tx.commit(); } catch (Exception e) { if (tx != null && tx.isActive()) { tx.rollback(); } // 业务异常处理逻辑 }
方案3:使用声明式事务
如果你的项目已经集成了Spring等支持声明式事务的框架,直接使用@Transactional注解管理事务,完全不需要手动编写事务开启、提交、回滚的逻辑,从根源避免手动操作事务导致的各类错误。
内容的提问来源于stack exchange,提问作者Ommadawn
相关产品推荐
相关产品推荐

