テーブル全体のロック方法について。
とあるテーブルのデータ全体を更新するトランザクション中に
他ユーザにテーブル自体触らせたくない!というとき等々に使う。
--------------------------------------------------
◆ロックの種類
--------------------------------------------------
こんなもん?
・排他ロック:他から参照も登録・更新・削除も指一本触らせない!ロック
・更新ロック:他から既存レコードの更新だけはさせないロック
・共有ロック:他から参照はできるが登録・更新・削除はさせないロック
--------------------------------------------------
◆テーブルロック方法
--------------------------------------------------
以下のsqlを実行すればロックできる。
SELECT * FROM TABLEA WITH(xxx)
xxx部分は後述参照。
--------------------------------------------------
◆テーブルロック方法
--------------------------------------------------
WITH内の文言と、ロックの種類、
そしてロックを取得したトランザクションと別のトランザクションからの
当テーブルの操作の可否について示す。
■(TABLOCK)
共有ロックをSQL実行中のみ保持
・select 可
・insert 不可
・update 不可
⇒あくまでSELECT文を実行中にロックされるだけなので、使いどころがない?
後述TABLOCK,HOLDLOCKのほうが実用的。
■(TABLOCK,HOLDLOCK)
共有ロックをトランザクション(BEGIN~COMMIT/ROLLBACK)終了まで保持。
・select 可
・insert 不可
・update 不可
⇒トランザクション中に他トランザクションから参照は可能だが
更新をさせたくないときに使える。
■(TABLOCKX)
排他ロックをトランザクション(BEGIN~COMMIT/ROLLBACK)終了まで保持。
・select 不可
・insert 不可
・update 不可
⇒更新だけでなく、参照もさせたくないときはこちら。
(TABLOCK, XLOCK)でも同様だが、コレはデッドロックが起きる(よく知らん)
■(UPDLOCK)
更新ロックをトランザクション(BEGIN~COMMIT/ROLLBACK)終了まで保持。
updateはできなくなるが、insertはできる点は注意。
更新だけさせたくないときに使う。
・select 可
・insert 可
・update 不可
--------------------------------------------------
◆テーブルロック解除方法
--------------------------------------------------
1)sp_whoコマンド実行
⇒blk列のプロセスIDをメモる。
2)殺す
SSMSで当該プロセスを殺す。(操作方法忘れた…)
※SSMSの利用状況モニタで先頭ブロックのプロセスを殺せばよい?たしか。
[参考]
http://msdn.microsoft.com/ja-jp/library/ms187373.aspx
http://www.atmarkit.co.jp/fdotnet/entwebapp/entwebapp09/entwebapp09_01.html
http://d.hatena.ne.jp/lpczclt/20080813/1218628250
http://development.station-t.com/SqlServer_Lock.htm
--------------------------------------------------
◆ロックエラーをわざと発生させる方法
--------------------------------------------------
異常系のテストを行いたい場合などで、テーブルのロックをかけたい場合の手順。
・以下のロック用SQLを実行(sleepしている間ロックされている)
BEGIN TRAN
SELECT * FROM TABLEA WITH(TABLOCKX)
WAITFOR DELAY '00:00:10' --任意の時間スリープ。
COMMIT TRAN
※デバッグ実行できるなら、COMMIT TRANまでにブレークしてもよい。
・エラーを起こすSQL
SET LOCK_TIMEOUT 0
SELECT * FROM TABLEA
⇒ロックタイムアウトの値を0にしているため、即時ロックエラーになる。
--------------------------------------------------
◆ダーティリード
--------------------------------------------------
ロック中のテーブルを参照したい場合は、WITH(NOLOCK)と末尾に書けばOK。
select * from table1 WITH(NOLOCK)