2011-07-12 10 views
4

私は本当に奇妙な問題を抱えています。なぜこれが起こっているのか、私は絶対に理解できません。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" /> 

、私はこの方法で例外を取得公共SmampiAccount loadSmampiAccountを(この行の長い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()はまだ呼び出されていません(通常はセッションを終了します)。 この1つのメソッドだけに専用のメソッド呼び出しごとに新しい休止状態のセッションを作成するので、別のメソッドがここで干渉しているとは考えられません。


編集

私は、セッションオープン状態にいくつかのデバッグ情報を追加しました:

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! 
+0

奇妙に見えます。 loadメソッド( 'System.err.println(session.isOpen());やそれに類するもの)の呼び出し前後で、セッションの状態を調べることをお勧めします。別の質問:load()の前に手動でセッションを閉じると、スタックトレースは同等ですか? – waxwing

+0

テスト目的のために、 ''に 'lazy =" false "'を追加すれば正常に動作しますか?また、どのHibernateのverisonを使用していますか? –

+0

@waxwing元の投稿にデバッグ情報を追加しました。結果は私にとって非常に奇妙に見えます。また、 'session.load(...)'の前に 'session.close()'を追加しようとしました。それは再び私に "セッションが閉じられている"例外を与えます。 'session.load(...)'の呼び出しの下で 'session.close()'を動かせば、 'org.hibernate.LazyInitializationException:この行にはプロキシを初期化できませんでした - セッションはありません 'というメッセージが表示されます:' List mailAccounts = smampiAccount.getMailAccounts(); ' – Timo

答えて

2

私は最大の馬鹿です世界。 defaultMailAccountのセッターで

が、私はこれを持っていた:

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(..)の呼び出しをメソッドの外側に移動すると、問題が解決されました。

お時間をいただき、ありがとうございました皆様にご迷惑をおかけします。

+0

私の提案:春をチェックし、「懸念の分離」を読んでください。 –

+0

私が見たときに何か変わっていたそのスタックトレースで:セッションが閉じられたことを認識する前に、コードに(遠くにonPostLoadに)遠くまで "遠く"行きました。私はこれをHibernateのバグとして提案しようとしていました。 – waxwing

関連する問題