JPA 如何跨所有相同的应用程序实例管理实体?



我对JPA有一些令人困惑的事情。

据我所知,JPA 具有持久性上下文(又名。L1 缓存(和 它管理所有实体的持久性。和 它使用以程管理实体。
1. 当 FIND 查询发生时,上下文中没有实体,因此实体管理器向数据库请求数据
2. 将结果另存为持久性 Contentext 中的实体。
3. 在此之后,当查询发生时,持久性查询返回内存实体(如果有(。

但是在第 3 个中,它在多个实例环境中的工作方式非常令人困惑。我认为,在多个应用程序实例中,它无法确保所有实例中的实体数据相同。

假设 JPA 应用程序有 2 个实例。(所有实例都是相同的负载均衡逻辑(。表有 2 列,一列是 ID,主键,另一列是名称 varchar。

有一行是id=1,name="foobar">

"实例 A"通过用户选择查询从数据库中生成 ID 等于 1 的实体。
此外,"实例 B"通过用户选择查询从数据库中生成 ID 等于 1 的相同实体。
然后"实例 A"更新实体,该实体为 ID=1 到 name="blahblah"通过用户更新查询。

经过足够长的时间后,没有对两个实例进行查询,如果更新查询是"从 name=blahblah 的表中更新名称设置新名称"发生在"实例 B"中,我很困惑,它已经有实体,它的名称可能不会更新为"blahblah"。 那么上次更新查询在 JPA 中是如何工作的呢?

编辑我意识到我的问题不清楚。因为 JPA 在提交事务时对 DBMS 执行数据库查询,所以通常有多少应用程序是没有问题的。

为了告诉你我为什么问这个,让我们假设有下面的代码。

void updateEntities() {
entityManager.getTransaction().begin();
List<MyEntity> entities = dao.findAll(); // point1
for (MyEntity e : entities) {
e.setValue(e.getValue() + 100); // point2
}
entityManager.getTransaction().commit();
}
List<MyEntity> findMyEntities() {
return dao.findAll(); // point3
}

两个在其代码中具有上述代码块的实例(两者都是用于负载平衡的相同代码实例(。(实体的数量足以容纳 RAM。

当客户端查询调用该方法时A instance在内存中生成实体时findMyEntities。然后
客户端发生下一个查询,然后请求到达instance Binstance B也生成了内存中的所有实体。 然后更新查询到达instance A和实例执行的 updateEntities 和内存中的所有实体instance A都进行了更新。
但此时,instance A的缓存实体和instance B缓存实体之间存在差异。但是instance B可能无法知道数据是否已更新。

所以我想知道在上述情况之后何时发生更新查询instance B,我相信如下

  1. 将发生用户查询。 因此将调用updateEntities方法。
  2. 在第 1 点中,JPA 立即对数据库执行实际查询,并将查询结果同步到实体上下文。
  3. Point2 代码块正常执行。

正确吗?

这是关于事务隔离和锁定的。如果要查看其他事务提交的更改,则需要刷新(实体(。JPA 不知道其他事务提交的更改。

bean 的类,通常用:

@Stateless没有状态,也就是说,即使另一个 Bean 请求相同的信息,它也不会保存状态。

您可以阅读:

https://www.tutorialspoint.com/ejb/ejb_stateless_beans.htm

@StateFul状态,将保存状态,并且在 Bean 结束事务之前不会更改。

您可以阅读:

https://www.tutorialspoint.com/ejb/ejb_stateful_beans.htm

并阅读以下内容:

https://docs.oracle.com/javaee/6/tutorial/doc/gipjg.html

除此之外,您还可以拥有以下方法(通过 EntityManager 和 EntityTransaction(:

  • 反转

  • 冲洗

  • 刷新

  • setFlushMode (( 可以有两个值,自动和提交

请参阅示例:

EntityManager em = ....
EntityTransaction et = em.getTransaction();
et.begin();
try{
em.persist(someObject);
et.commit();  
}
et.rollback();

最后,您可以指定要在 Bean 中使用的事务类型,这些事务可以是:

  • 命令的

  • 必填

  • REQUIRES_NEW

  • 支持

  • NOT_SUPPORTEED

  • 从不

要使用此属性:

@TransactionAttribute(TransactionAtributeType.NEVER)
public float division(float a,float b){
return (a/b);
}

这个问题源于我对 JPA L1 缓存寿命的误解。

提交事务或客户端请求结束时,L1 缓存失效(在 OSIV 中(。

所以在我看来,L1缓存不与线程或进程共享。
它仅在 OSIV 中的相同事务或相同请求有效。

因此,如果实例是否多个,则没有问题。

我很感激回答愚蠢问题的人。

最新更新