JPA-获取跨EntityManager的更新/同步的实体(刷新)

马可

我正在学习JPA。我的提供者是EclipseLink,我正在制作桌面应用程序,并使用由应用程序管理的EntityManager。在DB中,我有表B引用表A,这意味着实体类A具有B的列表(并且它还具有其他一些列表)。这是一种简化的情况:我有四种方法/场景可以使下面的方法所做的更改在调用方法及其EM中可见。

void addB(A a, String desc){
   EntityManager em = factory.createEntityManager();
   em.getTransaction().begin();
   mngedA = em.find(A.class, a.getId());
   B b = new B();
   b.setDesc(desc);
   // option 1:
   b.setA(mngedA);
   em.persist(b);

   // option 2:
   a.getBList().add(b);

   em.getTransaction.commit();
   em.refresh(a); //needed in some scenarios
   em.close();

}

在调用方法中,我有:

em = factory.createEntityManager();
A a = em.find(A.class, id);
println(a.getBList().size());
addB(a, "value1");

//em = factory.createEntityManager(); //1
//a = em.find(A.class, id);           //2
//em.refresh(a);                      //3

println(a.getBList().size());

标记行可以注释和不注释,我找出了4个组合,这些组合使第二个println调用比第一个更大的打印。这些是:

  1. 在addB中使用选项1(直接保留新实体),在addB中使用刷新。在调用方法中,仅使用= em.find ...(注释行标记为1和3)。

  2. 在addB中使用选项1,但仅在调用方法中使用刷新(取消注释行// 3保留行// 2注释)。

  3. 在addB中使用选项1,但不要在addB中使用刷新,在调用方法中使用刷新,并使用新em再次“查找” A(取消对所有3行的注释)。(与2几乎相同,但由于性能而有趣)

  4. 在addB中使用选项2,根本不使用刷新,在调用方法中取消对所有3行的注释。

第一种组合最慢,需要大多数SQL查询。刷新时将加载所有内容。第二和第三个组合在中间,刷新时仅加载来自数据库的更改。第四个示例是最快的,它不需要对数据库的任何其他查询。

有人可以对所有这些混乱,如何运作以及为什么起作用发表评论吗?

什么是正确的方法,是否有办法在不创建新EM而是使用现有EM的情况下实现第四组合的效果?

如果我想制作大型且复杂的桌面应用程序,该应用程序可能具有并发访问权限,那么我应该采用哪种方法?

谢谢你。

克里斯

如果必须使用其他EntityManager上下文,请记住,在其外部加载的实体不在其中,因此对mngedA所做的更改不会反映到A中,除非在事务完成后强制刷新。EntityManager设计为与事务作用域相似地使用,因此有意地将单独的EntityManager彼此隔离。

有许多解决方案可满足您的需求,但是如果您的客户端寿命长,则您可能不希望在单个EM的生命周期内保持这种状态,因为它确实包含一个缓存,该缓存将填满并变得陈旧。取而代之的是,您可能希望根据需要获得一个读取对象,并在完成后清除它,或者扔掉并根据需要获取新的对象。就像是:

A saveAndAddB(A a, String desc){
   EntityManager em = factory.createEntityManager();
   em.getTransaction().begin();
   mngedA = em.merge(a);
   B b = new B();
   b.setDesc(desc);
   b.setA(mngedA);
   mngedA.getBList().add(b);;
   em.persist(b);
   em.getTransaction.commit();
   em.close();
   return mngedA;
}

这将保存对A的所有更改,并从最新的EntityManager返回最新副本。然后,如果需要,您的应用程序将继续使用此A实例:

  em = factory.createEntityManager();
  A a = em.find(A.class, id);
  em.close();//no longer needed
  println(a.getBList().size());
  a = addB(a, "value1");

  println(a.getBList().size());

如果您的流程是短暂的,则另一种方法是将EM传递给该方法,以便可以在同一事务中接收所有更改,但是更常见的是传递分离的A实例,然后根据需要将它们合并到事务中。如果您不想获取对A的更改,则可以将A的ID传递给addB方法。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章