Shound我避免使用mappedBy来保持我的应用程序稳定? [英] Shound I avoid using mappedBy to keep my application stable?
问题描述
@Entity
public class Trip {
@OneToMany(mappedBy =trip,fetch = FetchType.LAZY)
private Set< Job> jobs = new HashSet< Job>();
$ b $ @实体
公共类工作{
@ManyToOne(fetch = FetchType.LAZY)
私人旅程跳闸;
问题在于mappedBy关系在不同情况下表现不同。这里是一个例子
EntityManager em1 = unit.createEntityManager();
EntityManager em2 = unit.createEntityManager();
//一个EM开始交易并存储一笔旅行
em1.getTransaction()。begin();
旅程=新旅程();
em1.persist(trip);
Long tripId = trip.getId();
assertThat(tripId).isPositive();
em1.getTransaction()。commit();
//然后em2启动不同的事务
em2.getTransaction()。begin();
//通过clean em查找旅程(缓存为空)
Trip em2Trip = em2.find(Trip.class,tripId);
Job job = new Job();
job.setTrip(em2Trip);
em2.persist(job);
// em2Trip不应该更新
assertThat(em2Trip.getJobs())。hasSize(1);
em2.getTransaction()。commit();
em1.getTransaction()。begin();
旅行em1Trip = em1.find(Trip.class,tripId);
//在这里失败
assertThat(em1Trip.getJobs())。hasSize(1);
em1.getTransaction()。commit();
上面的代码显示如果实体已经加载到实体管理器的缓存中, mappedBy关系可能会返回无效结果。
我有一个证明,它在JBoss下也不起作用。以下代码的行为有所不同,具体取决于正在使用哪个实体管理器。结果是不可预测的。
Trip trip = em.find(Trip.class,tripId);
if(trip.getJobs()。size()== 0)...
这是否意味着mappedBy在引入和使用后会自动生成应用程序错误?
PS我不想滥用冬眠。我只想知道是否有人遇到这样的问题,他们是如何应对的? 解决方案
与协会完全没有任何关系;如果您试图从两个实体经理读取/更新简单的POJO,您会得到完全相同的结果。一旦你的实体与持久性上下文相关联,它就不会自动从数据库中刷新。这是一种记录行为 - 在绝大多数情况下,这是一种DESIRED行为。
就保持应用程序稳定而言:
- EntityManager实例直接对应于休眠会话,因此不应长期保存。如果您重写上述代码以使用新的EntityManager实例(em3)而不是重复使用em1,则问题将消失。
- EntityManager具有
refresh()
方法,您可以调用它来从数据库重新加载实体状态。 - EntityManager有一个
clear()
方法这将完全清除持久化上下文,从而也防止了这个问题。虽然 - 调用clear()
而没有flush()
会抛弃所有挂起的更新,但谨慎谨慎地使用它。 / li>
I have two entities like the following:
@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;
}
The problem is that the mappedBy relationship behaves differently in different circumstances. Here is an example
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();
The code above shows that if an entity is already loaded in the entity manager's cache, the getter for the mappedBy relationship may return invalid results.
I have a proof it doesn't work under JBoss either. The following code behaves differently depending on which entity manager is being used. The result is unpredictable.
Trip trip = em.find(Trip.class, tripId);
if (trip.getJobs().size() == 0) ...
Does this mean that the mappedBy automatically makes application buggy as soon as it is introduced and used?
P.S. I am not trying to abuse hibernate. I only want to find out if someone faced such a problem and how did they cope with it
Behavior you're describing has absolutely nothing to do with associations; you would get the exact same results if you just tried to read / update simple POJO from two entity managers. Once your entity is associated with persistence context it will NOT be automatically refreshed from the database. This is a documented behavior - and in the vast majority of cases this is a DESIRED behavior.
As far as "keeping your application stable" goes:
- EntityManager instances directly correspond to Hibernate sessions and thus should not be held for prolonged periods of time. If you rewrite your code above to use a new EntityManager instance (em3) instead of reusing em1, your problem will go away.
- EntityManager has a
refresh()
method which you can invoke to reload entity state from the database. - EntityManager has a
clear()
method which will clear the persistence context completely thus preventing this issue as well. Use it sparingly and cautiously, though - invokingclear()
withoutflush()
will throw away all pending updates.
这篇关于Shound我避免使用mappedBy来保持我的应用程序稳定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!