WEBアプリがデータベースを更新するまでのパターン。
- 入力画面で情報を入力する。
- 確認画面で更新する情報を確認する。
- データベースを更新して、更新完了画面を表示する。
確認画面でデータベースにロックをかけて、データベースを更新するなんてことができると思えないから(できない…と思うけど)、毎画面、毎画面で少なくとも更新前には、データベースの情報が別スレッド、別プロセスに更新されていないかチェックが必要になると思う。
よくやるチェック方法は確認画面で更新対象のレコードの更新日時を取得して、データベースを更新する場合に、更新するレコードと突き合わせてみる。突き合せ方は以下の2通りぐらいかな。
- 更新日時をキーとして、データベースを検索。レコードがあれば更新、無ければNG。
- 更新日時をキーとして、データベースを更新。更新件数が1件以上ならばOK、0件ならばNG。
個人的には、チェックと実際の更新処理が1つのSQLですむ後者の方が好き。前者で、チェックするときに「SELECT FOR UPDATE」でロックをかけてもよいと思う。後者の方法ならDELETEでも使えそう。
INSERTの場合はどうするだろう…
INSERTの場合は、確認画面でユニークなIDを発行して、データベースの更新時にそのIDをINSERTする。同じ、IDが存在しなければOKだし、もしあれば…一意制約に引っかかるな。
SQLExceptionを補足して、エラー処理をしてもいいけど、できればSQLExceptionはフレームワーク側に処理させたい。
そうすると…
- (チェック)IDをキーにして、データベースを検索。
- (チェック)レコードがあればNG。
- (更新)INSERTする。
…この方法だと、チェックと更新にタイムラグがあるのがいやだ。1つのSQLで済ます方法か、チェックするときにレコードにロック(まだ存在していないレコードにロック?)する方法を考えてみよう…*1
*1:ふと思ったけど、設計によってはメソッド単位でロック(というかsynchronizedで同期)できるかも