Java 休眠中的延迟集合初始化失败
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18724797/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Lazy collection initialization fails in hibernate
提问by Alexz
Today I faced with next problem in hibernate:
今天我在休眠中面临下一个问题:
My method:
我的方法:
@Transactional
public Period getDefault(Team team) {
Period defaultPeriod = team.getDefaultPeriod();
List<Period> periods = _periodDAO.getPeriods(team);
if (!periods.contains(defaultPeriod)) {
defaultPeriod = periods.get(periods.size() - 1);
}
}
_periodDAO.initializeIssues(defaultPeriod);
return defaultPeriod;
}
Method initializeIssues:
方法初始化问题:
public void initializeIssues(Period period) {
if (period.getIssues() != null) {
Hibernate.initialize(period.getIssues());
}
}
I receive exception if collection periodscontains defaultPeriod
如果收集期包含defaultPeriod,我会收到异常
Caused by: org.hibernate.HibernateException: collection is not associated with any session
at org.hibernate.collection.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:474)
at org.hibernate.Hibernate.initialize(Hibernate.java:417)
But if I remove some lines and change method to
但是如果我删除一些行并将方法更改为
@Transactional
public Period getDefault(Team team) {
Period defaultPeriod = team.getDefaultPeriod();
_periodDAO.initializeIssues(defaultPeriod);
return defaultPeriod;
}
It works fine.
它工作正常。
I debugged first example and hibernate session does not close during whole method.
我调试了第一个示例,并且在整个方法期间休眠会话没有关闭。
As I understand, if loaded object (one element in periods) in session has collection which associated with active session and existing before object (defaultPeriod) also has same association - it (defaultPeriod) will lose its association.
据我了解,如果会话中加载的对象(句点中的一个元素)具有与活动会话相关联的集合,并且存在于之前的对象(defaultPeriod)也具有相同的关联 - 它(defaultPeriod)将失去其关联。
Is it truth? Who else faced with same problem?
是真的吗?还有谁遇到同样的问题?
Thank you for answers.
谢谢你的回答。
回答by Sotirios Delimanolis
Presumably, your Teamargument is coming from another transaction and another Hibernate Session.
据推测,您的Team论点来自另一个事务和另一个 Hibernate Session。
When a @Transactionalmethod returns, the TransactionManagercloses the Sessionwhich does some cleanup and unsets (sets to null) the Sessionfield of all PersistentCollectioninstances. Your defaultPeriodhas one of these in its issuesfield.
当一个@Transactional方法返回时,TransactionManager关闭 进行Session一些清理并取消设置(设置为null)Session所有PersistentCollection实例的字段。您defaultPeriod在其issues领域拥有其中之一。
Hibernate's Hibernate.initialize()forces the initialization of a lazy PersistentCollection, but has the following code (calls AbstractPersistentCollection#forceInitialization())
HibernateHibernate.initialize()强制初始化一个 lazy PersistentCollection,但具有以下代码(调用AbstractPersistentCollection#forceInitialization())
if ( session == null ) {
throw new HibernateException( "collection is not associated with any session" );
}
If you are planning on using the issuescollection outside the original @Transactionalmethod (the code that produces Team), you need to load the underlying objects. Either change it to EAGER loading or do what you are doing with Hibernate.initialize().
如果您计划在issues原始@Transactional方法(生成 的代码Team)之外使用集合,则需要加载底层对象。要么将其更改为 EAGER 加载,要么执行您正在使用的Hibernate.initialize().
Another solution is to make the Sessionlast longer than just the length of the first @Transactional, but I don't have details for that. A quick google or SO search should bring up some options.
另一种解决方案是使Sessionlast 比第一个的长度更长@Transactional,但我没有详细信息。快速 google 或 SO 搜索应该会提供一些选项。
This is what is happening
这就是正在发生的事情
Period defaultPeriod = team.getDefaultPeriod();
gets a Periodobject with id (ex.) 42. Because it happened in another Sessionthat has since been closed, the issuesis a PersistentCollectionwhich has a nullSessionreference, and will throw the Exceptionyou get.
获取一个Period带有 id (ex.)的对象42。因为它在另一个碰巧Session的是已被关闭,issues是一个PersistentCollection具有nullSession参考,并抛出Exception你。
The you do this
你这样做
List<Period> periods = _periodDAO.getPeriods(team);
Let's say the Listcontains a Periodobject with id 42, so the ifin
假设List包含一个Period带有 id的对象42,所以ifin
if (!periods.contains(defaultPeriod)) {
defaultPeriod = periods.get(periods.size() - 1);
}
doesn't get executed. Although the equals()returns true(contains()also returns trueand becomes falsebecause of !), the objects are not the same. The on in the Listhas an attached (non-null) Session, so that one can be initialized. But yours, the one held by defaultPeriodcannot.
不会被执行。虽然equals()返回true(contains()也返回true并成为false因为!),但对象并不相同。中的 onList有一个附加的 (non-null) Session,以便可以初始化。但你的,持有的defaultPeriod不能。

