0

在我的 Web 应用程序中,我经常需要在单个请求的范围内从数据库中读取实体,并稍后在另一个请求中刷新它们。目前我有一个辅助方法

protected <T> T refresh(T t) {
    if (!entityManager.contains(t)) {
        t = merge(t);
        entityManager.refresh(t);
    }
    return t;
}

他们的每个方法都会先刷新它正在处理的实体。如果实体已被刷新,则不会发生任何事情。

这很好用,直到后来我意识到这个解决方案有一个重大问题:如果实体已在数据库中同时被修改,则调用失败。merge显然merge无法“知道” 的内容t无论如何都会被立即调用refresh.

这个问题的正确解决方案是什么?到目前为止,我有这些想法,但没有一个感觉完全令人满意:

  1. 而不是调用mergeand refresh,获取实体的 ID 并调用

    t = find(theClassOfT, t.getId());
    

    这将解决问题,我会得到一个全新的实体,但它有一个主要缺点:我需要知道它的类T和它的 ID。获取 ID 可以通过为我的所有实体提供一个顶级超级接口来完成,但是获取类是有问题的(因为 JPA 实现可能会子类化实体,我担心调用t.getClass()可能会返回某些特定于实现的子类T)。

  2. 长期只保留 ID,并在每次请求期间读取实体的最新信息。从设计的角度来看,这似乎更正确(无论如何,陈旧的实体都携带无效信息),但再次需要T手头的类。

更新:我在请求中保留实体的原因仅仅是为了方便。我特别不需要确保在此期间没有修改实体 - 无论如何我都会在下一个请求时刷新它。

4

3 回答 3

1

你的#1应该工作。

object.getClass()应该为班级工作,因为你可以使用emf.getPersistenceUnitUtil().getIdentifier(object).

您也不能将属性传递Mapfind()操作,并且可以包括刷新查询提示(“eclipselink.refresh”="true" 或“javax.persistence.cache.storeMode”、“REFRESH”),这可以避免潜在的 2 个查询.

于 2013-08-14T14:58:49.073 回答
0

我认为您正在描述乐观锁定

一种方法是锁定实体,直到客户端提交更改 - 这将降低旅游应用程序的吞吐量。

或者使用乐观锁——你可以希望对象不会改变,将版本的标识符放在实体中。保存对象后,将根据数据库中的当前状态检查该数字,如果不匹配,因为另一个客户端更改了实体,此并发更新就会失败。一旦发生并发修改,您的应用程序必须能够解决状态。

于 2013-08-14T09:51:54.157 回答
0

如果您尝试从数据库中刷新实体,您可能做错了什么。

您的实体的寿命不应超过要求。您的 JPA 提供者应该处理缓存,因此调用相同的查询并再次检索相同的实体应该不会大惊小怪。因此,将您的实体存储在 @RequestScoped、@ConversationScoped 和类似范围内。

另一方面,如果您确实需要较长时间的实体,则应该考虑锁定。正如上一张海报所解释的,您可以这样做:

  • 悲观锁定,您可以在其中锁定实体并防止其他任何人在您提交之前对其进行更新
  • 乐观锁定,您希望实体不会被更新,但save()可能会失败

阅读更多关于锁定和 JPA 的信息,例如:http: //city81.blogspot.com/2011/03/pessimistic-and-optimistic-locking-in.html

于 2013-08-14T10:00:27.800 回答