8

いずれHOLDLOCKかを使用して、またはUPDLOCKトランザクション(T1など)で表示され、別のトランザクション(T2など)からの読み取りアクセスをブロックしません。

私が理解しているように、T1が完了するまで、HOLDLOCKT2による更新/削除は防止されます。およびaUPDLOCKは、T2による更新/削除/挿入を防止します。これらの両方で、T2はこれらのレコードへの読み取りアクセス権を持ちます。

ただし、両方を使用すると(:のようにHOLDLOCK, UPDLOCK)、読み取りアクセスからもT2がブロックされます。両方を使用するとどうなりますか?

あなたの洞察力をありがとう

アップデート:

それは私が見ているものではありません:

例えば:

クエリ1:

begin tran

select * from tblTest WITH (UPDLOCK, HOLDLOCK)

WAITFOR DELAY '00:00:10'

commit tran

クエリ2:

select * from tblTest 

クエリ2は、クエリ1が終了するまで結果を生成しません。

4

3 に答える 3

11

UPDLOCKロックの種類に影響します。これは、ロックではなくロックが取得されるSELECTステートメントを意味します。デフォルトの読み取りコミット レベルでは、データが読み取られるとすぐに解放されます。US

上記は、行とページのロックに適用されます。テーブル レベル ロックの BOL 状態の場合

UPDLOCK が TABLOCK と組み合わされている場合、または何らかの理由でテーブル レベルのロックが取得されている場合は、代わりに排他 (X) ロックが取得されます。

HOLDLOCKシリアル化可能な分離セマンティクスを取得するため、トランザクションが終了するまでロックが解放されず、少なくともクエリでカバーされる範囲全体がロックされてファントムの挿入が防止されます。

ロックは他のUロックと互換性がありますが、他のロックとは互換性SがありませんU(ロックの互換性マトリックスUPDLOCKを参照してください)。そのため、ロックが行またはページ レベルで取得された場合、ヒントを使用しない限り、他のリーダーはブロックされません。

ただし、オブジェクト レベルのXロックが取得された場合、UPDLOCKリーダーISテーブルのロックを取得しようとしてブロックされます。あなたの例のクエリでsys.dm_tran_locksは、2 番目のクエリがブロックされている間を見て、両方のトランザクションが持っている/待っているロックを確認してみてください。

あなたの質問のクエリについて

SELECT *
FROM   tblTest WITH (UPDLOCK, HOLDLOCK) 

Xクエリ プランがヒープのスキャンを示している場合、オブジェクトは常にロックされます。インデックス スキャンの場合は、使用されるロックの粒度に依存します (通常、テーブル レベルへのロックのエスカレーションは、少なくとも 5,000 回の下位レベルのロックが取得された後に試行されます)。

于 2013-01-10T18:20:59.453 に答える
4

マーティンupdlockは、排他ロック (+1) がどのように発生するかを既に説明していると思います...そして、これをコメント/質問として投稿したいと思いますが、私のコメントは大きすぎます...

これがロックのupdlock結果の簡単な例です...x

IF (OBJECT_ID('tblTest') IS NOT NULL)
    DROP TABLE tblTest

CREATE TABLE tblTest (
    ID INT NOT NULL
)

BEGIN TRANSACTION
    SELECT * FROM dbo.tblTest WITH (UPDLOCK, HOLDLOCK) WHERE ID = 1
    SELECT * FROM sys.dm_tran_locks WHERE request_session_id = @@SPID 
COMMIT

ただし、クラスター化インデックスをテーブルに追加すると、テーブルの排他ロックがなくなり、ロックに置き換えられRangeS-Uます...

ALTER TABLE dbo.tblTest 
ADD CONSTRAINT PK_tblTest 
PRIMARY KEY CLUSTERED (ID)

BEGIN TRANSACTION
    SELECT * FROM dbo.tblTest WITH (UPDLOCK, HOLDLOCK) WHERE ID = 1
    SELECT * FROM sys.dm_tran_locks WHERE request_session_id = @@SPID 
COMMIT

基本的に、このテーブルにクラスター化インデックスはありますか?

編集:

非クラスター化インデックスを使用した別の例...

IF (OBJECT_ID('tblTest') IS NOT NULL)
    DROP TABLE tblTest

CREATE TABLE tblTest (
    ID INT NOT NULL
)

CREATE NONCLUSTERED INDEX 
IX_tblTest ON dbo.tblTest (ID) 

BEGIN TRANSACTION
    SELECT * FROM dbo.tblTest WITH (HOLDLOCK) WHERE ID = 1
    SELECT * FROM sys.dm_tran_locks WHERE request_session_id = @@SPID 
COMMIT

RangeS-Sロックになってしまう…

しかし...

BEGIN TRANSACTION
    SELECT * FROM dbo.tblTest WITH (UPDLOCK, HOLDLOCK) WHERE ID = 1
    SELECT * FROM sys.dm_tran_locks WHERE request_session_id = @@SPID 
COMMIT

排他的なテーブルロックが発生します...

于 2013-01-10T18:49:57.047 に答える
1

テーブルにクエリに適切なインデックスがない場合、直列化可能な分離によりテーブル ロックが取得されます。HOLDLOCK により、serializable が言及されているテーブルの有効なトランザクション分離レベルになります。

これは、他の人が言及したエスカレーションと相まって、X表示される動作を引き起こします。

于 2013-01-10T18:51:13.533 に答える