gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 12:02:38 27 4
gpt4 key购买 nike

我正在学习 JPA。我的提供商是 EclipseLink,我正在制作桌面应用程序,并使用应用程序管理的 EntityManager。在数据库中,我有表 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中使用刷新。在调用方法中仅使用 a = em.find...(用 1 和 3 标记的注释行)。

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

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

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

第一个组合是最慢的,它需要最多的 SQL 查询。刷新时它会加载所有内容。第二个和第三个组合位于中间,刷新时它仅加载数据库中的更改。第四个示例是最快的,它不需要对数据库进行任何额外的查询。

有人可以对所有这些困惑发表评论吗,这是如何以及为什么有效?

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

如果我想制作大型且复杂的桌面应用程序,可能可以并发访问数据库,我应该采用什么方法?

谢谢。

最佳答案

如果您必须使用不同的 EntityManager 上下文,请记住在其外部加载的实体并不属于它的一部分,因此对 mngedA 所做的更改不会反射(reflect)到 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 方法。

关于java - JPA - 跨 EntityManager 获取更新/同步的实体(刷新),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27881058/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com