一个EntityManager看不到另一个EntityManager完成的更新

时间:2018-04-16 09:39:10

标签: hibernate jpa

我在使用RESOURCE_LOCAL事务类型的独立应用程序中使用两个EntityManager实例。我执行这样的操作:

  • 使用第一个EntityManager(em1)
  • 保存实体
  • 使用第二个EntityManager(em2)
  • 更新实体
  • 使用第一个EntityManager(em1)
  • 读取实体

问题是第3步的em1没有看到em2完成的更新。

EntityManagerFactory emf = Persistence.createEntityManagerFactory("test");

// Step 1: create entity
EntityManager em1 = emf.createEntityManager();
em1.getTransaction().begin();
Article article = new Article("article_1");
em1.persist(article);
em1.getTransaction().commit();

// Step 2: update entity
EntityManager em2 = emf.createEntityManager();
em2.getTransaction().begin();
Article articleForUpdate = em2.find(Article.class, 1L);
articleForUpdate.setName("updated article_1");
em2.persist(articleForUpdate);
em2.getTransaction().commit();

// Step 3: read updated entity
em1.getTransaction().begin();
Article updatedArticle = em1.find(Article.class, 1L);
em1.getTransaction().commit();

log.info("updated entity: {}", updatedArticle); // logs stale data

em1.close();
em2.close();
emf.close();

有人可以解释为什么em1会读取陈旧数据吗?

2 个答案:

答案 0 :(得分:1)

如果在请求数据库之前存在实体的引用,则EntityManager在其第一级缓存中首先查找 EntityManager变量引用的em1实例在缓存中具有Article实体,其ID为1,因为它已保留。 所以这个语句将从缓存中检索实体:

Article updatedArticle = em1.find(Article.class, 1L);

要防止此行为,您有多种方法:

  • 通过调用EntityManager.detach()
  • 将实体与EntityManager上下文分离
  • 通过调用EntityManager.refresh()从数据库刷新实体的状态。在这种情况下,不再需要find()查询。
  • 更激进:通过调用EntityManager
  • 清除EntityManager.clear()上下文

答案 1 :(得分:1)

EntityManger 1具有其文章对象的自己的缓存版本

直到它由它管理,它将为您提供旧版本。如果你想这样做,由两个不同的实体经理你应该使用 REFRESH 而不是find。

em1.refresh(article);

关于第一级缓存:LINK

关于刷新LINK