调用Criteria API的list()方法时抛出Session/EntityManager已关闭异常
问题:Criteria API调用
criteria.list()抛出Session/EntityManager已关闭异常 使用Criteria API从数据库获取记录时,调用
criteria.list()抛出java.lang.IllegalStateException: Session/EntityManager is closed异常,但其他使用Criteria API的功能运行正常。代码实现如下:
@Autowired @PersistenceContext(unitName = "logsEntityManagerFactory") private EntityManager entityManager; public Criteria createCriteria() { Session session = entityManager.unwrap(Session.class); return session.createCriteria(Script.class); } public List<Object> getPageContent(int from, int pageSize){ if(from < 0) return new ArrayList<>(); pageSize = Math.min(25, Math.max(10, pageSize)); Criteria criteria = createCriteria(); criteria.add(Restrictions.eq(Constants.TYPE, Constants.SCRIPT_TYPES.globalScript)); criteria.setFirstResult(from); criteria.setMaxResults(pageSize); return criteria.list(); // 抛出Session/EntityManager已关闭异常 }
问题原因
- 事务上下文缺失:当前
getPageContent方法未被Spring事务管理覆盖。Spring中,EntityManager/Session的生命周期默认绑定到事务上下文,没有事务时,EntityManager可能在完成createCriteria操作后就被容器回收关闭,导致后续调用list()时Session已失效。其他正常运行的方法大概率都添加了@Transactional注解,处于事务上下文内,Session会被保持打开状态。 - Session依赖EntityManager生命周期:通过
entityManager.unwrap(Session.class)获取的Session,其生命周期完全依赖于EntityManager。如果EntityManager没有处于事务中,无法保证在执行list()时仍处于有效状态。
解决方案
- 添加事务注解:在
getPageContent方法上添加@Transactional注解,指定对应数据源的事务管理器:
@Transactional(unitName = "logsEntityManagerFactory") public List<Script> getPageContent(int from, int pageSize){ if(from < 0) return new ArrayList<>(); pageSize = Math.min(25, Math.max(10, pageSize)); Criteria criteria = createCriteria(); criteria.add(Restrictions.eq(Constants.TYPE, Constants.SCRIPT_TYPES.globalScript)); criteria.setFirstResult(from); criteria.setMaxResults(pageSize); return criteria.list(); }
注:建议把返回值
List<Object>改为List<Script>,符合类型规范,避免后续类型转换问题。
- 验证事务配置一致性:对比其他正常运行的Criteria API方法,确认它们都处于
@Transactional注解的事务上下文内,以此验证事务缺失是本次问题的核心原因。
内容的提问来源于stack exchange,提问作者Malay Pandey
相关产品推荐
相关产品推荐

