Correct way to take a exclusive lock

半城伤御伤魂 提交于 2019-11-29 14:04:32

If you are only worried about other readers, then you shouldn't need exclusive locks, the pattern

Begin Transaction

  Make Data Inconsistent

  Make Data Consistent

Commit Transaction

Should be fine. The only sessions who will see inconsistent data are those that use nolock or Read Uncommitted, or those that expect to make multiple consistent reads without using Repeatable Rows or Serializable.

In answer to the question, the correct way to take an exclusive lock, in my opinion, is to arrange things so the engine does it for you.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!