Correct way to take a exclusive lock

后端 未结 2 1610
孤城傲影
孤城傲影 2020-12-20 21:08

I am writing a procedure that will be reconciling finical transactions on a live database. The work I am doing can not be done as a set operation so I am using two nested cu

2条回答
  •  心在旅途
    2020-12-20 21:44

    I couldn't believe that an XLOCK would not block a concurrent reader at read committed so I just reproduced it: It is true. Script:

    Session 1:

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    BEGIN TRAN
    
    SELECT * FROM T WITH (ROWLOCK, XLOCK, HOLDLOCK /*PAGLOCK, TABLOCKX*/) WHERE ID = 123
    

    Session 2:

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    BEGIN TRAN
    
    SELECT * FROM T WHERE ID = 123
    

    Plug in some table name that you have at hand. Session 2 is not being blocked.

    I also tried using a PAGLOCK but that didn't work either. Next I tried a TABLOCKX but that didn't work either!

    So your table-lock based strategy does not work. I think you'll have to modify the readers so that they either

    1. use snapshot isolation to get a consistent view (as of before any writes)
    2. use a higher isolation level to be blocked by the writer

    Of course there is a nasty workaround to really, really lock the table: alter its schema. This will take a Sch-M lock which conflicts with basically any access to the table. It even holds of some metadata read operations. It could look like this:

    --just change *any* setting in an idempotent way
    ALTER TABLE T SET (LOCK_ESCALATION = AUTO)
    

    I tested this to work.


    Is SQL Server right not obeying the XLOCK? Or is this a flaw in the product? I think it is right because it conforms to the documented properties of READ COMMITTED. Also, even using SERIALIZABLE there are cases where one transaction can lock a row exclusively and another can read the same row! This can happen in the presence of indexes. One transaction might X-lock on the non-clustered index IX_T_SomeCol while another happily reads off of the clustered index PK_T.

    So it is actually quite normal that transactions can execute independently even in the presence of exclusive locking.

提交回复
热议问题