有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我遇到了一个非常奇怪的问题,我完全无法理解为什么会发生这种情况

问题是这样的:

我得到了一个名为“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 smipaccount loadsmipaccount(long id)中得到一个异常:

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

Stacktrace:

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) 个答案

  1. # 1 楼答案

    我是世界上最大的白痴

    在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(..)的调用移到方法外部修复了这个问题

    很抱歉占用了大家的时间,谢谢大家的帮助