Hibernateでのトランザクションは、一般にJDBCでのトランザクションとほぼ同じです。 DataSource
からConnection
を取得すると、デフォルトでautocommit = trueに設定されます。そのため、autocommit = falseに変更されたトランザクションの場合も同様です。そうすれば、更新を行うたびに明示的にコミットされたときにのみ、データベースに変更が加えられます。
HibernateのSession
はいくつかのことを行いますが、この場合、その機能は第1レベルのキャッシュと同じです。パフォーマンスのために、キャッシュ内の変更をキューに入れ、必要に応じてデータベースにプッシュするという目的で、「トランザクションwritebehind」という概念を使用します。たとえば、永続的なインスタンスを取得し、複雑なマルチメソッドワークフローで変更する場合、各メソッドは何も変更しないか、複数の場合がありますが、Hibernateは更新のSQL文を1つだけ必要とします。これはトランザクションで実行しているかどうかに関係なく、常に発生します。
セッションキャッシュとアクティブトランザクションが一緒になって、アクティブなトランザクション中にフラッシュされます。 Hibernateは変更をフラッシュするためにできるだけ長く待つので、トランザクション中でなくてもフラッシュすると、変更はすぐにデータベースに永続的になります。つまり、データベースの書き込み回数を減らすためのパフォーマンスの最適化です。しかし、トランザクション中にセッションをフラッシュする場合は、変更をデータベースにプッシュします。ただし、データベースはトランザクション・キュー内の変更を保持します。したがって、データベースに入っていても、トランザクションをコミットするまで他の接続には表示されません。
理想的には、フラッシュは一切発生せず、トランザクションコミットによってコミット前にフラッシュがトリガされ、データベースに移動してコミットされていない変更を他の呼び出し元には見えないようにする回数が最小限に抑えられます。しかし、必要な回数だけフラッシュすることができます。
Hibernateを自動的にフラッシュする原因は、クエリです。私が言ったように、永続的なインスタンスを(削除しても)多くの変更を加えることができ、セッションキャッシュにキューイングされます。しかし、クエリ(動的ファインダ、基準、HQLなど)を実行すると、Hibernateはキューに入れられた変更がクエリに影響するかどうかを知ることができません。したがって、すべてのクエリが一貫していることを確認するのは悲観的なことです。データベースは、照会にフラッシュされたがコミットされていないデータを使用し、予期した結果を返します。これは、カスタムドメインクラスバリデーターでクエリを実行するときにwithNewSession
メソッドを使用することを推奨する理由で、奇妙な動作を引き起こす可能性がある検証中に現在のセッションがフラッシュされないようにするためです。