懒惰的集合初始化在hibernate中失败

时间:2013-09-10 16:55:49

标签: java hibernate collections lazy-initialization

今天我遇到了hibernate的下一个问题:

我的方法:

@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;
}

方法initializeIssues:

public void initializeIssues(Period period) {
    if (period.getIssues() != null) {
        Hibernate.initialize(period.getIssues());
    }
}

如果收集期间包含 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)

但是如果我删除一些行并将方法更改为

@Transactional    
public Period getDefault(Team team) {
    Period defaultPeriod = team.getDefaultPeriod();
    _periodDAO.initializeIssues(defaultPeriod);
    return defaultPeriod;
}

工作正常。

我调试了第一个示例,并且整个方法期间hibernate会话没有关闭。

据我了解,如果会话中的加载对象(句点中的一个元素)具有与活动会话关联的集合,并且对象之前存在( defaultPeriod )也具有相同的关联 - 它( defaultPeriod )将失去关联。

这是真的吗?还有谁面临同样的问题?

感谢您的回答。

1 个答案:

答案 0 :(得分:13)

据推测,您的Team参数来自另一个事务和另一个Hibernate Session

@Transactional方法返回时,TransactionManager会关闭执行某些清理的Session并取消设置(设置为null)所有Session字段PersistentCollection个实例。您的defaultPeriod字段issues中包含其中一个。{/ p>

Hibernate的Hibernate.initialize()强制执行惰性PersistentCollection的初始化,但是具有以下代码(调用AbstractPersistentCollection#forceInitialization()

    if ( session == null ) {
        throw new HibernateException( "collection is not associated with any session" );
    }

如果您计划在原始issues方法(生成@Transactional的代码)之外使用Team集合,则需要加载基础对象。将其更改为EAGER加载或使用Hibernate.initialize()执行您正在执行的操作。

另一个解决方案是让Session的持续时间长于第一个@Transactional的长度,但我没有详细说明。快速google或SO搜索应该提出一些选择。


这就是发生的事情

Period defaultPeriod = team.getDefaultPeriod();

获取带有id(例如)Period的{​​{1}}对象。因为它发生在另一个已被关闭的42中,Session是一个issues,其PersistentCollection null引用,并会抛出{{} 1}}你得到了。

你这样做

Session

假设Exception包含一个ID为List<Period> periods = _periodDAO.getPeriods(team); 的{​​{1}}对象,那么<{p}}中的List

Period

未执行。虽然42返回if if (!periods.contains(defaultPeriod)) { defaultPeriod = periods.get(periods.size() - 1); } 也会返回equals()并因true而变为contains()),但对象并不相同。 true中的on有一个附加的(非空)false,因此可以初始化一个。但你的,!所持的那个不能。