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

时间:2018-08-31 03:12:33

标签: java jpa

关于JPA,我有些困惑。

据我所知,JPA具有持久性上下文(也称为L1缓存),并且它管理所有实体以实现持久性。并通过以下过程管理实体。
1.发生查找查询时,上下文中没有实体,因此实体管理器向数据库请求数据
2.将结果另存为持久性目录中的实体。
3.之后,当查询发生时,持久性查询将返回内存实体(如果有)。

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

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

有一行ID = 1,名称为“ foobar”

“实例A”通过用户选择查询从数据库中生成ID等于1的实体。
同样,“实例B”通过用户选择查询从数据库中生成ID等于1的相同实体。
然后通过用户更新查询将ID = 1的“实例A”更新实体命名为“ blahblah”。

经过足够的时间后,没有对两个实例进行查询,如果在“实例B”中发生了更新查询,即“从名称= blahblah的表更新名称设置新名称”,我很困惑,它已经具有该实体及其实体名称可能未更新为“ blahblah”。那么最后更新查询在JPA中如何工作?

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

要告诉您为什么要问这个,让我们假设下面是代码。

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. 在point1中,JPA立即对db执行真实查询,并将查询结果同步到实体上下文。
  3. point2代码块正常执行。

对吗?

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

bean的类通常标记为:

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

您可以阅读:

PassNinja

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

您可以阅读:

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

阅读:

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

除此之外,您还可以使用方法(通过EntityManager和EntityTransaction):

  • 回滚

  • 冲洗

  • 刷新

  • 提交

  • setFlushMode()可以具有两个值:AUTO和COMMIT

查看示例:

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);
  }

答案 2 :(得分:0)

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

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

因此,就我而言,L1缓存未与线程或进程共享。
它仅对OSIV中的同一事务或相同请求有效。

因此,实例是否多个都没有问题。

我感谢回答愚蠢问题的人。