更新処理とロック処理

更新処理の流れ

  1. EntityManagerを取得する。(検索処理参照)
  2. トランザクション開始
  3. 更新処理(追加、修正、削除)
  4. コミット(トランザクション終了)
  5. EntityManagerをクローズする

実際のコードはこんな感じ。

EntityManager#merge(Object) で、追加・更新を行う。DB上に、対象のエンティティと同一のキーをもつレコードが存在していればUPDATE、なければINSERTをしてくれるので便利。

削除の場合は一旦mergeしてからEntityManager#remove(Object)を実行する。

楽観的ロック

DB更新時の排他処理について。

レコード毎にバージョン番号を持ち、まず最初に対象となるデータを取得しておき、更新時にDB上の対象データのバージョン番号に変化が無いか調べ、変化があれば「自分より前に、自分以外の誰かが更新した=このまま登録しては他人の変更を上書きしてしまうのでダメ」、変化がなければ「誰にも更新されていない=そのまま更新してよい=その一瞬だけロックして書き込んですぐに開放する」と判断するというのが楽観的ロック。CVS、SVNなどのリビジョン番号での管理がこれに当たる。

この楽観的ロックに関する機能がJPAには備わっているというので、使ってみた。方法は簡単、エンティティでバージョン番号を意味する列に「@Version」アノテーションを付加するだけ!

このようなエンティティクラスを使用して更新処理を行った場合、エラーの無い場合(新規登録時含む)はそのまま処理が進み、排他エラーになった場合はOptimisticLockExceptionが発生する。

悲観的ロック

俺はあまり好きではないので使わない悲観的ロックについて。

操作開始から終了までずっとロックしっぱなしにして、その間は他からの更新を許さないのが悲観的ロック。この場合、エンティティクラスに@Versionアノテーションなどは不要(別にあってもいいんだろうけど)。

これまた簡単にできるようだ。ロックをかける方法は主に以下の二つ。

  • 検索時にロック
  • 任意のタイミングでロック

確かに簡単。