gpt4 book ai didi

sql - 独占锁的正确获取方式

转载 作者:行者123 更新时间:2023-12-02 17:21:53 24 4
gpt4 key购买 nike

我正在编写一个程序,用于协调实时数据库上的财务交易。我正在做的工作无法作为集合操作完成,因此我使用两个嵌套游标。

在协调每个客户端时,我需要在事务表上获取独占锁,但我想释放锁并让其他人在我处理的每个客户端之间运行他们的查询。

我希望在行级别而不是表级别上执行独占锁定,但是 what I have read so far说如果其他事务在 READCOMMITED 隔离级别运行(这对我来说是这样),我就无法使用 (XLOCK, ROWLOCK, HOLDLOCK) 执行操作。

我是否正确地采用了表级排它锁,Server 2008 R2 中是否有任何方法可以使行级排它锁按我想要的方式工作,而无需修改数据库上运行的其他查询?

declare client_cursor cursor local forward_only for 
select distinct CLIENT_GUID from trnHistory
open client_cursor

declare @ClientGuid uniqueidentifier
declare @TransGuid uniqueidentifier

fetch next from client_cursor into @ClientGuid
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
begin tran

declare @temp int

--The following row will not work if the other connections are running READCOMMITED isolation level
--select @temp = 1
--from trnHistory with (XLOCK, ROWLOCK, HOLDLOCK)
--left join trnCB with (XLOCK, ROWLOCK, HOLDLOCK) on trnHistory.TRANS_GUID = trnCB.TRANS_GUID
--left join trnClients with (XLOCK, ROWLOCK, HOLDLOCK) on trnHistory.TRANS_GUID = trnClients.TRANS_GUID
--(Snip) --Other tables that will be "touched" during the reconcile
--where trnHistory.CLIENT_GUID = @ClientGuid

--Works allways but locks whole table.
select top 1 @temp = 1 from trnHistory with (XLOCK, TABLOCK)
select top 1 @temp = 1 from trnCB with (XLOCK, TABLOCK)
select top 1 @temp = 1 from trnClients with (XLOCK, TABLOCK)
--(Snip) --Other tables that will be "touched" during the reconcile

declare trans_cursor cursor local forward_only for
select TRANS_GUID from trnHistory where CLIENT_GUID = @ClientGuid order by TRANS_NUMBER
open trans_cursor

fetch next from trans_cursor into @TransGuid
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN

--Do Work here

END
fetch next from trans_cursor into @TransGuid
END

close trans_cursor
deallocate trans_cursor

--commit the transaction and release the lock, this allows other
-- connections to get a few queries in while it is safe to read.
commit tran
END

fetch next from client_cursor into @ClientGuid
END

close client_cursor
deallocate client_cursor

最佳答案

我不敢相信XLOCK不会在已提交的读取时阻止并发读取器,所以我只是重现了它:这是真的。脚本:

第 1 节:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN TRAN

SELECT * FROM T WITH (ROWLOCK, XLOCK, HOLDLOCK /*PAGLOCK, TABLOCKX*/) WHERE ID = 123

第二节:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN TRAN

SELECT * FROM T WHERE ID = 123

插入您手头的一些表名称。 session 2 未被阻止。

我还尝试使用PAGLOCK,但也不起作用。接下来我尝试了 TABLOCKX 但也不起作用!

所以你的基于表锁的策略不起作用。我认为你必须修改读者,以便他们要么

  1. 使用快照隔离来获得一致的 View (截至任何写入之前)
  2. 使用更高的隔离级别会被编写者阻止

当然,有一个令人讨厌的解决方法可以真正锁定表:更改其架构。这将采用 Sch-M 锁,该锁基本上与对表的任何访问都发生冲突。它甚至还保存一些元数据读取操作。它可能看起来像这样:

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

我测试过它是否有效。

<小时/>

SQL Server 不遵守XLOCK 是正确的吗?或者这是产品的缺陷?我认为这是正确的,因为它符合 READ COMMITTED 的记录属性。此外,即使使用SERIALIZABLE,在某些情况下,一个事务可以独占锁定一行,而另一个事务可以读取同一行!在存在索引的情况下可能会发生这种情况。一个事务可能会对非聚集索引 IX_T_SomeCol 进行 X 锁定,而另一事务则愉快地读取聚集索引 PK_T

因此,即使存在独占锁定,事务也可以独立执行,这实际上是很正常的。

关于sql - 独占锁的正确获取方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13435997/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com