使用SharedEntityManagerCreator创建EntityManager引发资源泄漏的解决方法
问题:手动创建EntityManager导致资源泄漏的解决方案选择
未使用
@PersistenceContext注解,而是手动通过如下方式创建EntityManager实例:private static final EntityManagerFactory entityManagerFactory = (EntityManagerFactory) ApplicationContextHolder.getContext().getBean("projEntityManagerFactory"); private Boolean update(String par) { EntityManager entityManager = SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory); StoredProcedureQuery query = entityManager.createStoredProcedureQuery(Constants.UPDATE_PROCEDURE); //other update query builder code return (Boolean) query.getOutputParameterValue(4); }目前出现资源泄漏相关警告,推测是因为EntityManager使用后未关闭。尝试了两种方案:1. 在方法上添加
@Transactional注解,使查询绑定事务,事务结束时自动关闭资源;2. 参考文档建议使用EntityTransaction并调用entityManager.close()关闭连接。请问哪种方案正确?如何解决该资源泄漏警告?
解决方案分析
方案1:使用@Transactional注解
该方案可行,且更符合Spring生态规范,前提是你的类需被Spring容器管理(即标注@Component/@Service等注解成为Bean)。
当方法被@Transactional修饰时,Spring会自动完成以下操作:
- 事务启动时,将EntityManager绑定到当前线程上下文
- 事务结束(提交/回滚)后,自动关闭EntityManager并释放资源
- 结合
SharedEntityManagerCreator创建的共享EntityManager,Spring会复用事务上下文内的实例,避免重复创建资源
只需给update方法添加注解即可:
@Transactional private Boolean update(String par) { EntityManager entityManager = SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory); StoredProcedureQuery query = entityManager.createStoredProcedureQuery(Constants.UPDATE_PROCEDURE); //other update query builder code return (Boolean) query.getOutputParameterValue(4); }
方案2:手动管理EntityTransaction并关闭EntityManager
该方案也能解决资源泄漏,但需要严格的手动资源管理,必须确保entityManager.close()在任何情况下都能执行,否则仍会出现泄漏。需用try-finally块包裹逻辑:
private Boolean update(String par) { EntityManager entityManager = SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory); EntityTransaction tx = null; try { tx = entityManager.getTransaction(); tx.begin(); StoredProcedureQuery query = entityManager.createStoredProcedureQuery(Constants.UPDATE_PROCEDURE); //other update query builder code Boolean result = (Boolean) query.getOutputParameterValue(4); tx.commit(); return result; } catch (Exception e) { if (tx != null && tx.isActive()) { tx.rollback(); } throw e; // 或根据业务需求处理异常 } finally { if (entityManager.isOpen()) { entityManager.close(); } } }
这种方式适合不受Spring事务管理的场景,但手动编码容易遗漏异常处理或资源关闭步骤,出错概率较高。
推荐方案
优先选择方案1,Spring的事务管理已封装了资源生命周期、事务提交回滚等逻辑,无需手动编写冗余代码,能有效避免资源泄漏,同时更贴合Spring开发的最佳实践。
内容的提问来源于stack exchange,提问作者user-newhc
相关产品推荐
相关产品推荐

