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 Team
argument is coming from another transaction and another Hibernate Session
.
据推测,您的Team
论点来自另一个事务和另一个 Hibernate Session
。
When a @Transactional
method returns, the TransactionManager
closes the Session
which does some cleanup and unsets (sets to null
) the Session
field of all PersistentCollection
instances. Your defaultPeriod
has one of these in its issues
field.
当一个@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 issues
collection outside the original @Transactional
method (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 Session
last 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.
另一种解决方案是使Session
last 比第一个的长度更长@Transactional
,但我没有详细信息。快速 google 或 SO 搜索应该会提供一些选项。
This is what is happening
这就是正在发生的事情
Period defaultPeriod = team.getDefaultPeriod();
gets a Period
object with id (ex.) 42
. Because it happened in another Session
that has since been closed, the issues
is a PersistentCollection
which has a null
Session
reference, and will throw the Exception
you get.
获取一个Period
带有 id (ex.)的对象42
。因为它在另一个碰巧Session
的是已被关闭,issues
是一个PersistentCollection
具有null
Session
参考,并抛出Exception
你。
The you do this
你这样做
List<Period> periods = _periodDAO.getPeriods(team);
Let's say the List
contains a Period
object with id 42
, so the if
in
假设List
包含一个Period
带有 id的对象42
,所以if
in
if (!periods.contains(defaultPeriod)) {
defaultPeriod = periods.get(periods.size() - 1);
}
doesn't get executed. Although the equals()
returns true
(contains()
also returns true
and becomes false
because of !
), the objects are not the same. The on in the List
has an attached (non-null) Session
, so that one can be initialized. But yours, the one held by defaultPeriod
cannot.
不会被执行。虽然equals()
返回true
(contains()
也返回true
并成为false
因为!
),但对象并不相同。中的 onList
有一个附加的 (non-null) Session
,以便可以初始化。但你的,持有的defaultPeriod
不能。