- ベストアンサー
DB2でのロック
Oracleで今まで開発しており今回始めてDB2での開発を行うものです。 Oraleと同じロックのかけ方をDB2で行いたいのですが、どのように記述すればよろしいでしょうか。 かけたいロックは ・セレクトした対象行のみにロックをかける ・他のセッションからは、ロック前の情報を参照可能 ・コミットまたはロールバックを行うまでロックを保持する です。 よろしくお願いします。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
OracleもDB2もデフォルトのトランザクション分離レベルはRead Committedですがトランザクション制御の実装の仕方が違います。 DB2は検索時に共有ロックをかけます。しかし読み取るデータが更新中の場合はすでにそのデータに排他ロックがかかっているので共有ロックをかけることができません。 Oracleはマルチ・バージョン一貫性制御でUNDO表領域に保持された更新前の情報を読み込むので読み取るデータが更新中であっても検索処理が待たされることはありませんがDB2は更新中のデータに他クライアントはアクセスできないで検索処理が待たされます。 Uncommitted Readでダーティー・リードを許す方法がありますが実用的なアプリケーションにあまり使用されません。 ロック取得時間を短くするような排他制御のアプリケーション設計を行い検索処理と重複するタイミングを減らすことで回避するようにします。オプティミスティックロックの実装方法を用いるようになると思います。 でも頻繁に複数ユーザーが同時に同一データを変更するようなシステムだと更新に失敗する確率が高くなり利便性が悪く場合があります。 SELECT * FROM TABLE FOR UPDATE WITH RS 排他制御が必要な際はその都度、各SQL文にWITH句を用いて分離レベルを指定してください。カーソルオープン前に発行することでCOMMITかROLLBACK時までロックされた状態になります。 ロック待機への対処も異なります。ロック待機をせずすぐに制御を戻す場合、OracleはSELECT~FOR UPDATEにNOWAITオプションを指定しますがDB2ではNOWAITオプションに対応する機能をサポートしていません。ロック待機する時間をLOCKTIMEOUTパラメータで指定するしかありません。 以上の辺を確認してみてください。
その他の回答 (1)
- O_cyan
- ベストアンサー率59% (745/1260)
>複数テーブルをJOINしたりすると・・ table2からID_cdを取得してそれをtable1のID_cdに更新をtable1のA_cdとtable2のA_cdでJOINしたい。みたいな感じのJOINなのでしょうか?詳細不明ですがJOINではなくexistsを使って update table1 set ID_cd = ( select ID_cd from table2 where table1.A_cd=table2.A_cd ) where exists ( select * from table2 where table1.A_cd=table2.A_cd ) こんな感じになるのでは 質問の内容と違っていたらゴメンなさい。
補足
O_cyanさん 説明が足りずすいません。 複数テーブルをJOINした形でロックをかけたいです。 その時に、FOR UPDATE をつけるとエラーが発生してしまいます。 例えば、 SELECT A.a, B.b FROM A INNER JOIN B ON A.ID = B.ID FOR UPDATE WITH RS と書いたときに、エラーとなってしまいます。 どのように記述すれば回避できるか教えていただけますでしょうか。 よろしくお願いします。
補足
O_cyanさん 回答ありがとうございます。 もう少し質問させてください。 FOR UPDATE WITH RS と教えて頂いたのですが、複数テーブルをJOINしたりすると FOR UPDATE でエラーが出てしまいます。 その場合はどのようにしたら良いのでしょうか。