我有点面临挑战,我有一个具有单向 OnetoMany 列表的实体所以我们有
Track
和 TrackVersions versions
的列表
Track {
@OneToMany(mappedBy = "track", cascade = CascadeType.ALL) // lazy by default
private final List<TrackVersion> versions = new ArrayList<>();
}
然后我有删除
TrackVersions
的服务Track
.....
@PersistenceContext
private EntityManager entityManager;
@Transactional
public void deleteTrackVersions(Track track) {
entityManger.flush();
entityManger.clear();
trackVerionRepo.deleteTrackVerions(track.getVersions); // This is a JPQL query that deletes track version where track version IN (? givenTrackVersions param)
..... some other logic
}
但是每当
trackVerionRepo.deleteTrackVerions(track.getTrackVersions)
执行它失败
failed to lazily initialize a collection of role: Track.versions, could not initialize proxy - no Session; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: Track.versions, could not initialize proxy - no Session
发生的事情是
entityManager.clear()
清除了持久性上下文,导致 verisons
被延迟加载被删除。所以任何连续的加载请求都会导致LazyInitializedExcpetion
但根据我的理解,只要有一个打开的
Transaction
因此一个打开的HibernateSession
所以没有理由发生LazyException
,那个懒惰的集合应该再次加载!
注意:我知道 hibernate 中类似的
LazyInitilizationExcpetion
错误的帖子,但在这种情况下,我特别询问为什么它发生在 entityManager.clear()
之后
这是由于
entityManager.clear()
电话而发生的。根据 specifications,一旦您调用 entityManager.clear()
持久性上下文中的所有托管实体都将被分离 - 主要是 Track
方法参数中接收的 deleteTrackVersions
实体。而且,正如您所说,@OneToMany
映射默认使用延迟加载。
一旦
Track
实体变得分离,是否还有一个活跃的交易并不重要。除非您先重新附加 TrackVersion
实体,否则您将无法检索相关的 Track
实体。
要将实体重新附加到持久性上下文,您可以使用
entityManager.merge()
方法。不过,考虑到您提供的代码,我只是删除了entityManager.clear()
电话。
作为一个无关的说明,你不能盲目相信懒加载映射配置;这是对持久性提供者的提示,但不能保证会被观察到。