8

今天我在休眠中遇到了下一个问题:

我的方法:

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

方法初始化问题:

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

它工作正常。

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

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

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

谢谢你的回答。

4

1 回答 1

13

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

@Transactional方法返回时,TransactionManager关闭Session执行一些清理并取消设置(设置为nullSession所有PersistentCollection实例的字段。您在其领域defaultPeriod拥有其中之一。issues

HibernateHibernate.initialize()强制初始化一个 lazy PersistentCollection,但有以下代码(调用AbstractPersistentCollection#forceInitialization()

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

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

另一种解决方案是使Sessionlast 比 first 的长度更长@Transactional,但我没有详细信息。快速 google 或 SO 搜索应该会出现一些选项。


这就是正在发生的事情

Period defaultPeriod = team.getDefaultPeriod();

获取一个Period带有 id (ex.) 的对象42。因为它发生在另一个Session已经关闭的地方,所以issuesPersistentCollection有一个null Session引用,并且会抛出Exception你得到的。

你这样做

List<Period> periods = _periodDAO.getPeriods(team);

假设List包含一个Period带有 id 的对象42,所以ifin

   if (!periods.contains(defaultPeriod)) {
        defaultPeriod = periods.get(periods.size() - 1);
   }

不会被执行。虽然equals()返回truecontains()也返回true并成为false因为!),但对象并不相同。中的 onList有一个附加的 (non-null) Session,因此可以对其进行初始化。但你的,持有的defaultPeriod不能。

于 2013-09-10T16:59:58.947 回答