トランザクション管理にSpringを使用する場合、Hibernateによる同時更新の処理方法(Hibernateのメモリ内自動バージョン管理)、またはデータベースにバージョン列を配置して同時更新を手動で処理する必要がある場合、誰かに説明してもらえますか?
トランザクション管理にSpringを使用しているかどうかは実際には重要ではなく、同時実行管理に関しては関係ありませんが、これは実際にはHibernateによって処理されます。 Hibernateは、2つの戦略を使用して、同時更新を処理できます。楽観的ロックと悲観的ロックです。
楽観的
楽観的ロックを使用する場合は、特別な属性(数値、タイムスタンプ)をバージョンとしてマップします。 (つまり、実際にはそのための列があります)。このバージョンは、エンティティを取得して含まれるときに読み取られます。 更新中のwhere句でインクリメント Hibernateによる。
これがどのように機能するかを説明するために、Personエンティティをid =1で、現在のバージョン=1でロードするとします。保存後、Hibernateは次のような処理を実行します:
update PERSON set ID=1, NAME='NAME 1', VERSION=2 where ID=1 and VERSION=1;
したがって、ここで、2つの同時トランザクションが実行されており、それぞれが同じをロードしていると想像してください。 エンティティ(同じバージョン番号)と名前の変更。
トランザクション#1が最初にコミットされ、次のクエリが実行されるとしましょう。
update PERSON set ID=1, NAME='NAME 1', VERSION=2 where ID=1 and VERSION=1;
成功し、バージョンがインクリメントされます。
次に、トランザクション#2がコミットされ、次のクエリが実行されます。
update PERSON set ID=1, NAME='NAME 2', VERSION=2 where ID=1 and VERSION=1;
where句はどのレコードとも一致しないため、これは何も更新しません。ここで、楽観的同時実行性の例外が発生します。
この戦略は、接続を維持しない場合、同時アクセスが頻繁ではない場合に適切であり、拡張性が非常に高くなります。もちろん、バージョン属性をマップする限り、すべてがHibernateによって透過的に処理されます。
悲観的
悲観的ロックを使用する場合、Hibernateは、レコードを使い終わるまで(通常はSELECT ... FOR UPDATE
を使用して)排他的に使用するためにレコードをロックします。 )。同じレコードにアクセスしようとする他の同時トランザクションは、ロックが解除されるまで中断されます。この戦略は、パフォーマンスを犠牲にして、より優れた予測可能性を提供し、無期限に拡張することはありません。
参考資料
- Hibernateコアリファレンスガイド
- 11.3。楽観的同時実行制御
- 11.4。悲観的なロック