Aggavara

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

採番用テーブルによってidの採番を行う場合、「SELECT ... FOR UPDATE」を使えばよい、というのがここ1年で覚えた知識のひとつ。ただ、あまり深くは理解していませんでした。

一番の疑問点は、「FOR UPDATE」という文字列の指す意味。ふつうに訳すと「更新のための」となり、照会は問題なく行えそうな気がしてきます。仮に照会が行えるとしたら、極めて近いタイミングのアクセスがが発生した場合、重複したidができる可能性があることになってしまいます。

また、ロックの種類はおおまかに共有ロック(照会可能、更新不可)と排他ロック(照会・更新とも不可)があるようです。FOR UPDATEで実際に排他ロックが獲得できているのか、そのあたりも気になります。

というわけで、現案件Java×DB2で調べてみることにしました。原始的な方法しか思い浮かばない自分にとっては、デバッグモードのあるEclipseは都合がよかったです。

検証

手順は以下です。

  1. トランザクションを有効にする
  2. 採番用テーブルからレコードを取得
  3. その直後にEclipseブレークポイントを設定
  4. アプリケーションの停止中に、CSESQL実行して検証
--SQL例
select VALUE from ID_GENERATOR where KEY = 'EMPLOYEE_ID' for update with rs

SELECTによる照会は、FOR UPDATEの有無で2通り検証しています。更新に関しては、ふつうにUPDATEでidの値を更新できるかどうかです。

DB2は「分離レベル」というものでロックの強度を指定できるようなので、その違いで検証しています。

分離レベル「UR
単純な照会
FOR UPDATEつき照会
更新
分離レベル「CS

※初期設定では、WITH句がない場合と同じ

単純な照会
FOR UPDATEつき照会
更新
分離レベル「RS」
単純な照会
FOR UPDATEつき照会 ×
更新 ×
分離レベル「RR
単純な照会
FOR UPDATEつき照会 ×
更新 ×
FOR UPDATE OF ...

「FOR UPDATE OF (カラム名)」という指定方法もあるようです。WITH句と共存できるかどうかは試してないのですが、とりあえず以下のSQLではどちらもロックがかかりませんでした。

select VALUE from ID_GENERATOR where KEY = 'EMPLOYEE_ID' for update of VALUE
select VALUE from ID_GENERATOR where KEY = 'EMPLOYEE_ID' for update of KEY
単純な照会
FOR UPDATEつき照会
更新

まとめ

DB2でテーブルによる採番を行う場合、以下のようにすればidの重複は起こらないといえます。

  • FOR UPDATE句を指定する
  • WITH句で分離レベルを「RS」か「RR」にする

※少しでも同時実行性を高めるために、「RR」よりも「RS」を指定するのがいいと思われます。

また言葉の意味についてですが、「FOR UPDATE」が修飾しているのはロックではなく、照会なのだと思います。「(後に)更新するための照会」であるがゆえに、ロックが必要、というわけですね。おそらく。

参考リンク

@IT:RDBMSアーキテクチャの深層(4)  OracleDB2、ロッキング・メカニズムはこれだけ違う
http://www.atmarkit.co.jp/fdb/rensai/rdbmsarc04/rdbmsarc04_1.html

DB2 Universal Database  分離レベル
http://publib.boulder.ibm.com/infocenter/db2luw/v8/index.jsp?topic=/com.ibm.db2.udb.doc/admin/c0004121.htm

DB2 UDB V8.1 デザイン・ガイド:ロック -基礎編- 
http://www-06.ibm.com/jp/domino01/mkt/dminfo.nsf/doc/000D73E3

浮浪プログラマの始末書:[DB] 排他制御
http://blog.livedoor.jp/froo/archives/50661135.html
posted on 2012-09-29 16:40  Aggavara  阅读(4809)  评论(0编辑  收藏  举报