大型过程中的 SQL 隔离级别或锁
Posted
技术标签:
【中文标题】大型过程中的 SQL 隔离级别或锁【英文标题】:SQL Isolation levels or locks in large procedures 【发布时间】:2014-03-28 12:06:22 【问题描述】:我有处理用户操作的大型存储过程。
它们由多个选择语句组成。这些被过滤,大多数时候只得到一行。选择被复制到临时表中或以其他方式评估。 最后,合并语句在数据库中进行所需的更改。 一切都封装在一个事务中。
我有来自用户的并发输入,应该锁定选择语句的选定行以保持数据完整性。
如何锁定所有选择语句的选定行,以便在当前事务正在进行时不会通过其他事务更新它们?
ROWLOCK 和 HOLDLOCK 的表提示组合是否以仅锁定选定行的方式工作,还是因为 HOLDLOCK 而锁定整个表?
SELECT *
FROM dbo.Test
WITH (ROWLOCK HOLDLOCK )
WHERE id = @testId
我可以改用吗
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
交易开始后?或者这会锁定整个表吗? 我正在使用 SQL2008 R2,但如果 SQL2012 中的工作方式有所不同,我也会感兴趣。
PS:我刚刚阅读了有关 UPDLOCK 和 SERIALIZE 的表提示。 UPDLOCK 似乎是只锁定一行的解决方案,而且似乎 UPDLOCK 总是锁定而不是 ROWLOCK,它只指定锁是基于行的 IF 锁。我仍然对解决这个问题的最佳方法感到困惑......
【问题讨论】:
您有几个问题都包含在文档中。你为什么认为 HOLDLOCK 会改变锁? 我知道 holdlock 强制锁定,并希望结合 rowlock 只锁定单行。我澄清了问题,我可以删除问题后的所有内容,但也许有助于理解问题。 【参考方案1】:更改隔离级别解决了问题(并锁定在行级别):
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
这是我测试它的方法。 我在 SQL Management Studio 的空白页中创建了一条语句:
begin tran
select
*
into #message
from dbo.MessageBody
where MessageBody.headerId = 28
WAITFOR DELAY '0:00:05'
update dbo.MessageBody set [message] = 'message1'
where headerId = (select headerId from #message)
select * from dbo.MessageBody where headerId = (select headerId from #message)
drop table #message
commit tran
在执行此语句时(由于延迟,最后需要 5 秒),我在另一个窗口中调用了第二个查询:
begin tran
select
*
into #message
from dbo.MessageBody
where MessageBody.headerId = 28
update dbo.MessageBody set [message] = 'message2'
where headerId = (select headerId from #message)
select * from dbo.MessageBody where headerId = (select headerId from #message)
drop table #message
commit tran
我很惊讶它会立即执行。这是由于默认的 SQL Server 事务级别 "Read Commited" http://technet.microsoft.com/en-us/library/ms173763.aspx 造成的。由于第一个脚本的更新是在延迟之后完成的,因此在第二个脚本期间还没有未提交的更改,因此读取并更新了第 28 行。
将 Isolation 级别更改为 Serialization 可以防止这种情况发生,但也可以防止并发 - 两个 scipts 都是连续执行的。
没关系,因为两个脚本都读取并更改了同一行(通过 headerId=28)。在第二个脚本中将 headerId 更改为另一个值,这些语句是并行执行的。所以 SERIALIZATION 的锁似乎在行级别。
添加表格提示
WITH ( SERIALIZABLE)
在第一个语句的第一个选择中也确实会阻止进一步读取所选行。
【讨论】:
以上是关于大型过程中的 SQL 隔离级别或锁的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因
mysql,oracle,sql server中的默认事务隔离级别查看,更改