我应该避免使用mappedBy来保持我的应用程序稳定吗?

时间:2009-08-14 13:00:00

标签: hibernate jpa jboss

我有两个实体,如下所示:

@Entity
public class Trip {

    @OneToMany(mappedBy = "trip", fetch = FetchType.LAZY)
    private Set<Job> jobs = new HashSet<Job>();

}

@Entity
public class Job {

    @ManyToOne(fetch = FetchType.LAZY)
    private Trip trip;

}

问题是mappedBy关系在不同情况下表现不同。这是一个例子

    EntityManager em1 = unit.createEntityManager();
    EntityManager em2 = unit.createEntityManager();

    // One EM starts transaction and stores a trip
    em1.getTransaction().begin();

    Trip trip = new Trip();
    em1.persist(trip);

    Long tripId = trip.getId();

    assertThat(tripId).isPositive();

    em1.getTransaction().commit();

    // Then em2 starts different transaction
    em2.getTransaction().begin();

    // Looking up for the trip through clean em (cache is empty)
    Trip em2Trip = em2.find(Trip.class, tripId);

    Job job = new Job();
    job.setTrip(em2Trip);

    em2.persist(job);

    // The em2Trip should not be updated

    assertThat(em2Trip.getJobs()).hasSize(1);

    em2.getTransaction().commit();

    em1.getTransaction().begin();

    Trip em1Trip = em1.find(Trip.class, tripId);

    // fails here
    assertThat(em1Trip.getJobs()).hasSize(1);

    em1.getTransaction().commit();

上面的代码显示,如果实体已经加载到实体管理器的缓存中,则mappedBy关系的getter可能会返回无效结果。

我有一个证明它在JBoss下也不起作用。以下代码的行为有所不同,具体取决于正在使用的实体管理器。结果是不可预测的。

        Trip trip = em.find(Trip.class, tripId);
        if (trip.getJobs().size() == 0) ...

这是否意味着mappedBy会在引入和使用后立即自动使应用程序出错?

P.S。我不是在试图滥用hibernate。我只是想知道是否有人遇到这样的问题以及他们是如何应对的?

2 个答案:

答案 0 :(得分:2)

您所描述的行为绝对没有与关联有关;如果您只是尝试从两个实体管理器读取/更新简单的POJO,您将获得完全相同的结果。一旦您的实体与持久性上下文相关联,它就不会自动从数据库中刷新。这是一种记录在案的行为 - 在绝大多数情况下,这是一种理想的行为。

就“保持应用程序稳定”而言:

  1. EntityManager实例直接对应于Hibernate会话,因此不应长时间保持。如果您重写上面的代码以使用新的EntityManager实例(em3)而不是重用em1,那么您的问题就会消失。
  2. EntityManager有一个refresh()方法,您可以调用该方法从数据库重新加载实体状态。
  3. EntityManager有一个clear()方法,可以完全清除持久化上下文,从而防止出现此问题。尽管如此谨慎谨慎地使用它 - 在没有clear()的情况下调用flush()会丢弃所有挂起的更新。

答案 1 :(得分:1)

使用mappedBy(即双向关联)没有错误或不一致。但是,配置起来很棘手,你必须非常小心地使用它 - 它不是一个神奇的子弹,如果你不遵循编程指南,你可以让你的实体进入一个不一致的状态。

因此我倾向于避开它们;我只使用它们,如果我真的需要双向关联,根据我的经验,这是非常罕见的。