1

との2つの操作を持つWebサービスで構成されるWebアプリケーションがcreateAありcreateBます。ハンドラーがエンドポイントに登録されます。このハンドラーはセッションを開き、要求を受信するとトランザクションを開始します。次に、要求された操作のコードが実行されます。応答が返送される前に、トランザクションがコミットされ、セッションが閉じられます。

のコードはcreateA、タイプのエンティティを作成し、メソッドAを使用してそれを永続化することで構成されています。Session.save()DEBUGモードでは、Session.save()が呼び出された後、セッションのActionQueueに1つの挿入があることがわかります。

のコードは次のものでcreateB構成されています。

  • 以前に作成されたタイプのエンティティを取得するA
  • Bのインスタンスを参照するエンティティを作成しますA(Bには、関連付けられたを表すプロパティがありますA
  • Aの新しいインスタンスを参照するように更新していますB
  • Session.save()の新しいインスタンスを呼び出すB
  • Session.update()の新しい変更されたインスタンスを呼び出すA

ただし、DEBUGモードでは、Session.save()andを呼び出した後Session.update()、対応するセッションのActionQueueは空になります。しかし、トランザクションがコミットされた後、データベースに作成されたエンティティを確認できます。

操作createAcreateBは、DEBUGなしでこの順序で呼び出されます。条件とメソッドを使用して以前に作成されBたインスタンスを取得しようとすると、作成の実行中にエラーが表示されます。問題は、のインスタンスが見つからないことです。ASession.list()A

ただし、DEBUGで同じ操作シーケンスを繰り返すかThread.sleep(15s)、2つの操作の呼び出しの間に使用すると、のインスタンスAが見つかります。

ありがとう


編集:特定のマシンでは動作するが、他のマシンでは動作しないことを正確に忘れました。そして、これらのマシンの間に違いは見られません。

4

2 に答える 2

1

createAとcreateBの両方に同じHibernateセッションを使用する場合、それは機能します。これを実現するために、HibernateセッションをHttpセッションに保存できます(同じブラウザーセッションからの要求は異なるスレッドで発生する可能性があるため、セッションオブジェクトへのアクセスを同期するように注意してください)。

問題は、Hibernateがセッションごとに新しいデータベース接続を開くことです。これで、データベースがステートメントを同期していないようです。データベースでは、挿入が完了する前に選択が到着する可能性があります。次に、この状態が発生するかどうかは、関係するコンピューターの速度に依存します。デバッグモードまたはsleep()を使用すると、1台のコンピューターの速度が低下するため、問題が発生しなくなります。

これらの2つの手順で2つの異なるセッションを続行する場合は、次のことができます。

  • データベースのトランザクションモードを探します。一部のデータベースには、正しいロックまたは同期が行われないダーティリードがあります。このようなモードを誤って使用していないか確認してください。
  • タイミングと同期を変更するデータベースのパラメーターがある場合は、JDBCパラメーター(休止状態のconnection.urlで使用できます)を確認してください。
  • 接続プールを確認します(使用している場合)。
于 2012-06-07T14:25:28.223 に答える
1

問題は、Session.save()を呼び出したときに、Hibernateがエンティティをデータベースに保存しないことです。後で実行するためにステートメントを準備するだけです。これは、トランザクションが終了したとき、またはセッションをフラッシュしたときに発生します。

Bへの呼び出しは、A要求のトランザクションが終了する前に発生している可能性があります。そのため、少し待つと機能します。

保存呼び出しの後にsession.flush()を追加してみてください。これにより、HibernateはDBへの変更を永続化するように強制されます。

于 2012-06-07T14:36:37.153 に答える