【问题标题】:exclusive lock and shared lock for select statement - SQL Server选择语句的独占锁和共享锁 - SQL Server
【发布时间】:2014-10-01 13:30:50
【问题描述】:

我无法理解 select 在独占事务中的行为方式。请考虑以下场景——

场景 1 步骤 1.1

create table Tmp(x int)
insert into Tmp values(1)

步骤 1.2 - 会话 1

begin tran
set transaction isolation level serializable 
select * from Tmp

步骤 1.3 - 会话 2

select * from Tmp

即使第一个会话还没有完成,会话 2 将能够读取 tmp 表。我认为 Tmp 将具有排他锁,并且不应发出共享锁来选择会话 2 中的查询。而且它没有发生。我已确保默认隔离级别为 READ COMMITED。

提前感谢您帮助我理解这种行为。

编辑:为什么我需要在排他锁中选择?

我有一个实际生成顺序值的 SP。所以流量是-

  1. 从表中读取最大值并将值存储在变量中
  2. 更新表设置值=value+1

此 SP 由数千个实例并行执行。如果两个实例同时执行 SP,那么它们将读取相同的值并更新 value+1。虽然我希望每次执行都有顺序值。我认为只有当 select 也是独占锁的一部分时才有可能。

【问题讨论】:

标签: sql sql-server locking shared isolation


【解决方案1】:

如果您希望事务可序列化,则必须在开始最外层事务之前更改该选项。因此,您的第一个会话不正确,并且实际上仍在读取已提交(或对该会话有效的任何其他级别)下运行。

但是即使你更正了语句的顺序,它仍然不会为普通的SELECT语句获取排他锁。


如果你想让普通的SELECT获得排他锁,你需要请求它:

select * from Tmp with (XLOCK)

或者你需要执行一个实际上需要排他锁的语句:

update Tmp set x = x

您的第一个会话需要独占锁,因为它不会更改数据。如果您的第一个(可序列化)会话已经运行完成并且回滚或提交,那么在您的第二个会话开始之前,该会话的结果仍然是相同的,因为您的第一个会话没有更改数据 - 因此“可序列化”交易的性质是正确的。

【讨论】:

  • 我有一个实际生成顺序值的 SP。所以流程是 - 1. 从表中读取最大值并将值存储在变量中 2. 更新表 set value=value+1 这个 SP 由数千个实例并行执行。如果两个实例同时执行 SP,那么它们将读取相同的值并更新 value+1。虽然我希望每次执行都有顺序值。我认为只有当 select 也是独占锁的一部分时才有可能。
  • 从资源使用的角度来看,实际生成没有间隙的序列号非常昂贵,尤其是在面对多个连接时。这就是 为什么 内置生成器(例如 IDENTITY 列和自 2012 年以来的序列)不提供这样的保证。您确定您需要这样的保证并且不能只使用内置功能吗?
  • 我同意你的看法,我们正面临一些问题,但现在不可能改变设计。但是,对我来说,为什么我不能对 select 语句进行独占锁定似乎是一个有效的问题?
  • 你可以 - 我在我的回答中展示了如何做 - 你必须使用 XLOCK 提示明确要求它。
  • 是的,我试过了,效果很好。但是,我无法理解为什么“设置事务隔离级别可序列化”不适用于 select 语句。使用“设置事务隔离级别可序列化”和“XLOCK”获得的排他锁有区别吗?我应该知道“设置事务隔离级别可序列化”不适用于选择语句而 XLOXK 有效吗?
猜你喜欢
  • 1970-01-01
  • 2015-04-16
  • 2012-08-03
  • 1970-01-01
  • 2014-11-15
  • 1970-01-01
  • 1970-01-01
  • 2014-08-11
  • 1970-01-01
相关资源
最近更新 更多