2

私はmysqlとhibernate 4とc3p0でジャージーを使用しています。休止状態を構成し、現在のセッション コンテキスト クラスをスレッドに設定する初期化サーブレットを作成しました。セッションを取得およびコミットするための静的メソッドを含む hibernateUtils クラスを作成しました。フィルターを使用して、受信要求でセッションを開始し、応答時にコミットします。

問題は、いくつかのランダムな間隔で org.hibernate.TransactionException: nested transactions not supported 例外が発生することですが、フィルターを除いて新しいセッションを作成しようとはしていません。

間違っている場合は訂正してください。ただし、現在のセッション クラスをスレッドに設定する場合、hibernateutil でスレッドローカルを作成する必要はありません。hibernate がこれを行います。だから私の質問は、これはそれを処理する安全な方法ですか?ランダムな間隔でエラーが発生する原因は何ですか?

====================== 編集 =========================

以前にコードを投稿しなかったことをお詫び申し上げます。したがって、フィルタは ContainerRequestFilter,ContainerResponseFilter を実装します

私がやっているリクエストフィルターで

Session session = sessionfactory.getCurrentSession();
session.getTransaction().begin();
session.setDefaultReadOnly(readOnly);

そして応答で

Transaction transaction = sessionfactory.getCurrentSession().getTransaction();
try {
    if (transaction != null && !transaction.wasCommitted()
       && !transaction.wasRolledBack() && transaction.isActive()) {
        transaction.commit();
    }
} catch (HibernateException e) {
    Transaction transaction = sessionfactory.getCurrentSession().getTransaction();
    try {
        if (transaction != null && transaction.isActive()) {
            transaction.rollback();
        }
    } catch (HibernateException e) {

    } finally {
         Session session = sessionfactory.getCurrentSession();
         try {
              if (session != null && session.isOpen()) {
                  session.close();
              }
         } catch (HibernateException e) {
            log.error("Closing session after rollback error: ", e);
            throw e;
     }

}

4

1 に答える 1

1

フィルターでプログラムによるトランザクション境界を使用しているようです (私が理解している限り)。したがって、各トランザクションを適切に終了することを再確認してください。リクエスト中に追加するものは気にしないでください (つまり、例外が発生した場合はロールバックし、それ以外の場合はコミットします)。

try {
    session.getTransaction().begin();
    // call the filter chain
    session.getTransaction().commit()
}
catch (RuntimeException e) {
    session.getTransaction().rollback();
}

コードがないと確認するのは難しいですが、一部のリクエストでは、トランザクションを適切に終了しなかったと思います (つまり、コミットまたはロールバックによって)。そのため、トランザクションはスレッドに関連付けられたままになり、スレッドはスレッド プールに戻ります (関連付けられているトランザクションがまだ存在するため、非常に奇妙な状態になります)。その後、別の要求が同じスレッドを再利用し、新しいトランザクションがフィルターに作成されます。 ...そして、例外があります。

編集

あなたのコードを注意深く見た後、それは私の仮定を確認します。

次の場合の流れを見てくださいtransaction.wasRolledBack()==true: コミットもロールバックもされません。

また、 Transaction.wasRolledBack()の javadoc の場合:

このトランザクションはロールバックされましたか、またはロールバックのみに設定されましたか?

トランザクションが「ロールバックのみ」とマークされている場合: true を返しますが、トランザクションが終了したことを意味するわけではありません。これは、トランザクションの唯一の可能な終了状態が「RollBack」であることを意味します。

しかし、一方で、同じ javadoc にも次のように書かれています。

戻り値: boolean このローカル トランザクションを介してトランザクションがロールバックされた場合は true。それ以外の場合は false。

私はそれが曖昧であることに気づきました。

だから私はこれを行うことをお勧めします:

if (transaction != null && !transaction.wasCommitted()
   && !transaction.wasRolledBack() && transaction.isActive()) {
    transaction.commit();
}else if(transaction.wasRolledBack()){
    transaction.rollback();
}
于 2013-09-12T20:57:58.910 に答える