我有两个实体,如下所示:
@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。我只是想知道是否有人遇到这样的问题以及他们是如何应对的?
答案 0 :(得分:2)
您所描述的行为绝对没有与关联有关;如果您只是尝试从两个实体管理器读取/更新简单的POJO,您将获得完全相同的结果。一旦您的实体与持久性上下文相关联,它就不会自动从数据库中刷新。这是一种记录在案的行为 - 在绝大多数情况下,这是一种理想的行为。
就“保持应用程序稳定”而言:
refresh()
方法,您可以调用该方法从数据库重新加载实体状态。clear()
方法,可以完全清除持久化上下文,从而防止出现此问题。尽管如此谨慎谨慎地使用它 - 在没有clear()
的情况下调用flush()
会丢弃所有挂起的更新。答案 1 :(得分:1)
使用mappedBy
(即双向关联)没有错误或不一致。但是,配置起来很棘手,你必须非常小心地使用它 - 它不是一个神奇的子弹,如果你不遵循编程指南,你可以让你的实体进入一个不一致的状态。
因此我倾向于避开它们;我只使用它们,如果我真的需要双向关联,根据我的经验,这是非常罕见的。