一个EntityManager无法识别另一个EntityManager的更新问题
问题根源:EntityManager的持久化上下文隔离
这是JPA的正常行为——每个EntityManager实例都维护着自己独立的持久化上下文(一级缓存),在RESOURCE_LOCAL事务类型下,这种隔离性会被进一步强化:
- 当你用
em1保存实体后,该实体的快照就被存入了em1的本地缓存 em2更新实体时,只会修改数据库和自己的缓存,完全不会同步到em1的缓存中- 所以第三步
em1读取时,会优先从自己的缓存里取旧数据,自然看不到em2的更新
可行的解决方案
根据你的业务场景,推荐以下几种解决方式:
1. 强制刷新em1的缓存
直接让em1从数据库重新加载实体,绕过本地缓存:
// Step 3 读取实体时,调用refresh方法 YourEntity targetEntity = em1.find(YourEntity.class, entityId); em1.refresh(targetEntity); // 这一步会从数据库拉取最新数据覆盖缓存
或者在JPQL查询时设置刷新提示,强制从数据库获取:
Query query = em1.createQuery("SELECT e FROM YourEntity e WHERE e.id = :id"); query.setParameter("id", entityId); // 设置提示让查询跳过缓存,直接读数据库 query.setHint("javax.persistence.cache.storeMode", "REFRESH"); YourEntity targetEntity = (YourEntity) query.getSingleResult();
2. 重建em1实例
如果你的业务流程允许,关闭旧的em1后重新创建一个新实例——新的EntityManager缓存是空的,读取时会直接从数据库获取最新数据:
// Step 1 完成保存操作后,及时关闭em1 em1.getTransaction().commit(); em1.close(); // Step 3 需要读取时,重新创建em1 EntityManager em1 = emf.createEntityManager(); YourEntity targetEntity = em1.find(YourEntity.class, entityId); // 此时拿到的是em2更新后的版本
3. 确保em2的事务已提交(关键前提)
别忘了确认em2的更新操作已经提交事务,否则数据库里也不会有最新数据,em1无论怎么读都拿不到更新:
// Step 2 em2更新实体后必须提交事务 em2.getTransaction().begin(); em2.merge(updatedEntity); em2.getTransaction().commit(); // 这一步不能少!
关于RESOURCE_LOCAL的补充提醒
RESOURCE_LOCAL是本地事务模式,设计上就强调每个EntityManager的独立性,所以不同实例之间看不到对方的缓存更新是预期行为。如果你的业务需要频繁跨EntityManager共享数据,可能需要考虑调整事务模式或者优化实体的访问逻辑。
内容的提问来源于stack exchange,提问作者ako
相关产品推荐
相关产品推荐

