休眠:“会话已关闭”,但从未关闭(手动)

时间:2011-07-12 12:28:50

标签: java hibernate session

我在这里遇到了一个非常奇怪的问题,我完全不明白为什么会这样。

问题如下:

我有一个名为“SmampiAccount”的课程,其中包含电子邮件帐户列表。映射文件看起来像这样(缩短):

<hibernate-mapping>
    <class name="com.smampi.web.model.account.SmampiAccount" table="SMAMPIACCOUNT">
            <id name="id" type="long" access="field">
                    <column name="SMAMPI_ACCOUNT_ID" />
                    <generator class="native" />
            </id>

            <bag name="mailAccounts" table="MAILACCOUNTS" lazy="false" inverse="true">
                    <key column="SMAMPI_ACCOUNT_ID"></key>
                    <one-to-many class="com.smampi.web.model.mail.account.MailAccount"/>
            </bag>
    </class>
</hibernate-mapping>

我通过这种方法得到了这个类的实例:

public SmampiAccount loadSmampiAccount(long id) throws FailedDatabaseOperationException {

    SmampiAccount smampiAccount = null;
    Session session = null;
    Transaction transaction = null;
    try {
        session = getSession();
        transaction = session.beginTransaction();
        smampiAccount = (SmampiAccount) session.load(com.smampi.web.model.account.SmampiAccount.class, id);
        List<MailAccount> mailAccounts = smampiAccount.getMailAccounts();
        doSomething(mailAccounts);
        transaction.commit();
    } catch (Exception e) {
        rollback(transaction);
        closeSession();
        throw new FailedDatabaseOperationException(e);
    } finally {
        closeSession();
    }

    return smampiAccount;
}

private Session getSession() {
    if (_session == null) {
        _session = getSessionFactory().openSession();
    }
    if (_session.isOpen() == false) {
        _session = getSessionFactory().openSession();
    }
    return _session;
}

这样可以正常使用。

现在,我想在映射文件中添加一个新属性,以便保存对默认电子邮件帐户的引用:

<many-to-one name="defaultMailAccount" column="DEFAULT_MAIL_ACCOUNT_ID" />

现在,我在此行中的方法 public SmampiAccount loadSmampiAccount(long id)中得到一个例外:

List<MailAccount> mailAccounts = smampiAccount.getMailAccounts();

堆栈跟踪:

org.hibernate.SessionException: Session is closed!
    at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:72)
    at org.hibernate.impl.SessionImpl.getPersistenceContext(SessionImpl.java:1954)
    at org.hibernate.event.def.DefaultPostLoadEventListener.onPostLoad(DefaultPostLoadEventListener.java:49)
    at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:250)
    at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:982)
    at org.hibernate.loader.Loader.doQuery(Loader.java:857)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
    at org.hibernate.loader.Loader.loadEntity(Loader.java:2037)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:86)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:76)
    at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3293)
    at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:496)
    at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:477)
    at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:227)
    at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:147)
    at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:1090)
    at org.hibernate.impl.SessionImpl.immediateLoad(SessionImpl.java:1026)
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:176)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
    at com.smampi.web.model.account.SmampiAccount_$$_javassist_19.getMailAccounts(SmampiAccount_$$_javassist_19.java)

这怎么可能? 会话未手动关闭,.commit()尚未调用(通常会关闭会话)。 另一种方法也不可能在这里干扰因为我为每个方法调用创建了一个新的hibernate会话,这个方法专用于这个方法。


修改

我在会话开放状态上添加了一些调试信息:

session = getSession();

System.err.println(session.isOpen());
transaction = session.beginTransaction(); // 1 (true)

System.err.println(session.isOpen()); // 2 (true)
smampiAccount = (SmampiAccount) session.load(com.smampi.web.model.account.SmampiAccount.class, id);

System.err.println(session.isOpen()); // 3 (true)
List<MailAccount> mailAccounts = smampiAccount.getMailAccounts(); // Throws exception that session is closed
doSomething(mailAccounts);

System.err.println(session.isOpen()); // 4 (not called)
transaction.commit();

这给了我:

true
true
true
org.hibernate.SessionException: Session is closed!

1 个答案:

答案 0 :(得分:2)

我是世界上最大的白痴。

在defaultMailAccount的setter中,我有这个:

public void setDefaultMailAccount(MailAccount defaultMailAccount) {
    this.defaultMailAccount = defaultMailAccount;
    try {
        databasecontroller.update(this);
    } catch (FailedDatabaseOperationException e) {
        handleException(e, false, null, null);
    }
}

每当Hibernate尝试从数据库加载持久版本并且再次导致会话关闭时,对databasecontroller.update(this)的调用就会导致级联。

databasecontroller.update(..)的调用移到该方法之外解决了问题。

很抱歉大家花时间感谢您的帮助!