Hibernate: «Сессия закрыта», хотя никогда не закрывается (вручную) - PullRequest
4 голосов
/ 12 июля 2011

У меня тут действительно странная проблема, и я совершенно не могу понять, почему это происходит.

Проблема выглядит так:

Я получил класс под названием «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();

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() еще не вызывается (что обычно закрывает сеанс). Также невозможно, чтобы здесь вмешивался другой метод, потому что я создаю новый сеанс гибернации для каждого вызова метода, который выделен только для этого одного метода.


Редактировать

Я добавил отладочную информацию о статусе открытия сеанса:

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 Ответ

2 голосов
/ 12 июля 2011

Я самый большой идиот в мире.

В установщике defaultMailAccount у меня было следующее:

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

Вызов databasecontroller.update(this) вызывал каскад всякий раз, когда Hibernate пыталсязагрузите постоянную версию из базы данных, и это снова привело к закрытию сеанса.

Перемещение вызова databasecontroller.update(..) за пределы метода решило проблему.

Извините всех за то, что вы взяли вашвремя и спасибо за помощь!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...