web-dev-qa-db-ja.com

結果を返さずに意図的にテーブルをロックする

更新スクリプトで、いくつかのテーブルをロックしています。

BEGIN TRANSACTION
    SELECT Top 0 Null FROM TableA with (holdlock, tablockx)
    SELECT Top 0 Null FROM TableB with (holdlock, tablockx)
    ...

実際のスクリプト結果に集中するために、結果を抑制したいと思います。結果セットを取得せずにテーブルをxlockするエレガントな方法はありますか?

empty result in ssms

3
VV5198722

他の方法もあるかもしれませんが、このテクニックは十分にシンプルに見えます:

SET NOCOUNT ON
BEGIN TRANSACTION
declare @DummyVariable INT
SET @DummyVariable = (SELECT  Top 0 Null FROM Test1 with (holdlock, tablockx))
8
Scott Hodgin

次のように一致しないwhere句を使用して一部のレコードを更新できます。

テスト設定:

CREATE TABLE locktest (id int, sometext nvarchar(50));

INSERT INTO locktest (id, sometext) VALUES
(1, 'dqsmfkqdsfjm'),
(2, 'qmsdfmdj'), 
(3, 'qkfjmsdfjk');

次に、1つのクエリウィンドウで次を実行します。

BEGIN TRAN;
UPDATE locktest WITH (tablockx)  SET id=null WHERE 1=2;

実行するまで、別のクエリウィンドウのSELECTinがブロックされていることがわかります

COMMIT TRAN;

これにより、結果セットを返さずにテーブルがロックされます。 0 rows affectedメッセージを抑制したい場合は、追加できます

SET NOCOUNT ON;

更新をブロックするだけで、読者に引き続き表を読み取らせたい場合は、次のように使用できます。

UPDATE locktest WITH (tablock, updlock)  SET id=null WHERE 1=2;

最も簡単な方法は sp_getapplock を使用することですが、排他的アクセスのためにこれを行うとシリアル化可能な同時実行を強制しているので、それはひどい考えです。

sp_getapplock @Resource = 'MyTable', @LockMode = 'Exclusive'; 

ただし、これはリソースを実際にロックするのではなく、アプリケーションの論理ロックのみです。 OPステートメントを読んだとき、何かを実行しようとしているスクリプトまたはアプリケーションがあるため、実際にテーブルをロックすることは良い考えだとは思いませんでした。テーブルをロックすると、テーブルへのシリアル化されたアクセスが効果的に発生します。さらに悪いことに、スクリプトでデッドロックが発生し、全員のアクセスが事実上拒否されるため、このアプリケーションロックの例を可能な代替手段として提供しました。このようにして、アプリケーションのロックをチェックしたり、スクリプト内の必要な部分を取得したりすることができますが、システムは他の機能状態のままになります。

OPが本当にテーブルをロックしてシリアル化されたアクセスを提供する必要がある場合、分離レベルをserializableに変更するか、スクリプトまたはアプリケーションの機能を再考する価値があります。

1
Sean Gallardy