1

私は2つのスレッドでJava/Seam / Hibernate /Glassfishアプリケーションを開発しています:

  • スレッド#1は、さまざまなメッセージを送信し、要約情報をMySQLデータベースに書き込みます。
  • スレッド#2は、データベースを定期的にポーリングし(によって呼び出されますScheduledExecutorService)、各メッセージの現在の「状態」に基づいて動作します。

統合テストの問題に遭遇しました:スレッド#2がスレッド#1によって新しい行が追加されるのをどれだけ待つかは問題ではないようです。テスト中に追加されないため、期待される呼び出しは行われません。 。確かに、テストが失敗した後、新しい行がポップアップしますが、遅すぎます。これが設計上の問題である可能性があるかどうかはわかりません-スレッド#2は現在、を使用してSeamコンテキストを取得していますLifecycle.beginCall()...Lifecycle.endCall()。したがって、私の理解(間違っている可能性があります)は、2つのスレッドに対して2つの別々のHibernateセッションがあることが原因である可能性があります-したがって、1つの読み取りは1つの書き込みからの最新情報を知りませんか?

save()これを修正する方法はいくつかあるかもしれませんが、私の現在の考えでは、トランザクションを呼び出したりflush()、手動でコミットしたりしたときに、Hibernateに実際にレコードをテーブルにすぐに追加するように強制することはできませんか?これらのいずれにも運がありません-舞台裏で使用されているある種の管理されたトランザクションがあるかどうか疑問に思います。アドバイスに感謝します...

詳細については、レコードを追加するコードの要点を次に示します。

// Obtain Hibernate session
Session session = (Session) Component.getInstance("hibernateSession");

// Create request
Request newRequest = new Request();
// newRequest.set<blah>();

// Save the new request to the database
session.save(newRequest);

// Have tried session.flush(), transaction.commit() etc. here.
// Nothing seems to put the record into the database straight away.

これが適切かどうかはわかりませんが、Hibernateの構成は次のとおりです。

<property name="transaction.flush_before_completion">true</property>
<property name="connection.release_mode">after_statement</property>
<property name="transaction.manager_lookup_class">org.hibernate.transaction.SunONETransactionManagerLookup</property>
<property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
<property name="current_session_context_class">jta</property>

(これはお客様が所有する既存のアプリケーションであるため、Hibernateの構成を変更する権利はありません。)

4

2 に答える 2

1

あなたの推測は良いです。

を使用しているJTATransactionFactoryため、トランザクションは JTA によって (つまり、コンテナによって) 境界付けられます。

を保存するために使用しているメソッドRequest(ここでは EJB で定義されていると仮定します) は、トランザクション注釈で注釈を付ける必要がある@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)ため、メソッドが終了すると、トランザクションがコミットされます。

于 2013-02-13T12:56:54.523 に答える
0

@Carlo Pellegrini に感謝します。その答えは私を正しい方向に向けてくれました。それ以来、この回答に出くわし、save() 操作の後に次のコードを試しました。

// Commit Seam-managed transaction (if there is one)
UserTransaction userTransaction = (UserTransaction) Component.getInstance("org.jboss.seam.transaction.transaction");
if (userTransaction.isActive()) {
    userTransaction.commit();
}

それはうまく機能しますが、私はそれが好きではありません - 少しハッキーなようです! より良い方法はありますか?

于 2013-02-13T17:01:31.960 に答える