何时/什么锁在READ COMMITTED隔离级别中保持/释放

Pri*_*esh 17 t-sql sql-server locking isolation-level

我试图了解SQL Server中的隔离/锁定.

我在READ COMMITTED隔离级别中有以下场景(默认)

我们有一张桌子.

create table Transactions(Tid int,amt int)

with some records

insert into Transactions values(1, 100)
insert into Transactions values(2, -50)
insert into Transactions values(3, 100)
insert into Transactions values(4, -100)
insert into Transactions values(5, 200)
Run Code Online (Sandbox Code Playgroud)

现在从msdn我明白了

当选择被触发时,共享锁被占用,因此没有其他事务可以修改数据(避免脏读).文档还讨论了行级,页级,表级锁.我想到了下面的观点

Begin Transaction

select * from Transactions

/*
some buisness logic which takes 5 minutes

*/

Commit
Run Code Online (Sandbox Code Playgroud)

我想要了解的是获取共享锁的持续时间以及(行,页,表).

只有在语句select * from Transactions运行时才会获取锁定,或者在我们达到COMMIT之前将整个5分钟获取锁定.

Rem*_*anu 21

你问的是错误的问题,你关心的是实现细节.您应该考虑和关注的是隔离级别的语义.Kendra Little有一张漂亮的海报解释他们:免费海报!SQL Server隔离级别指南.

你的问题应该改为:

从项目中选择*

问:我会看到什么项目?
答:所有承诺的项目

问:如果有未插入的事务已插入/删除/更新项,会发生什么?
答:您的SELECT将阻塞,直到所有未提交的项目都已提交(或回滚).

问:如果运行上述查询插入/删除/更新新项目会发生什么?
答:结果尚未确定.您可能会看到一些修改,不会看到其他一些修改,并且可能阻塞它们中的一些修改.

一旦您的陈述完成,READ COMMITTED就不会做出承诺,与交易的长度无关.如果再次运行该语句,您将再次具有与之前状态完全相同的语义,并且您之前看到的项目可能会更改,消失并且可能会出现新项目.显然,这意味着您可以在选择后对项目进行更改.

更高的隔离级别提供更强的保证:REPEATABLE READ保证在您提交之前,您第一次没有选择的项目可以被修改或删除.SERIALIZABLE增加了保证,在您提交之前,第二个选择中不会出现任何新项目.

这是您需要了解的内容,而不是实现机制的工作原理.掌握了这些概念后,您可以询问实施细节.它们都在" 事务处理:概念和技术"中描述.


Luc*_*ean 13

你的问题很好.了解获取哪种锁可以深入理解DBMS.在SQL Server中,在所有隔离级别下(Read Uncommitted,Read Committed(默认),Repeatable Reads,Serializable)为Write操作获取独占锁.

无论隔离级别如何,当事务结束时都会释放独占锁.

隔离级别之间的差异是指获取/释放共享(读取)锁定的方式.

在Read Uncommitted隔离级别下,不会获取共享锁.在此隔离级别下,可以发生称为"Dirty Reads"的并发问题(允许事务从已被另一个正在运行的事务修改但尚未提交的行中读取数据,因此可以回滚).

在Read Committed isolation level下,为相关记录获取共享锁.当前指令结束时释放共享锁.此隔离级别可防止"脏读",但由于记录可由其他并发事务更新,因此"不可重复读取"(事务A检索行,事务B随后更新行,事务A稍后再次检索同一行) .事务A检索同一行两次,但看到不同的数据)或"幻像读取"(在事务过程中,执行两个相同的查询,第二个查询返回的行集合与第一个不同)可能发生.

在"可重复读取"隔离级别下,将为事务持续时间获取共享锁.防止"脏读"和"不可重复读",但仍可能发生"幻读".

在Serializable隔离级别下,将为事务持续时间获取范围内的共享锁.上述并发问题均未发生,但性能大幅降低,存在死锁发生的风险.


Asi*_*sif 6

锁只会在select * from Transaction运行时获取

您可以使用以下代码进行检查

打开一个sql会话并运行此查询

Begin Transaction

select * from Transactions

 WAITFOR DELAY '00:05'
/*
some buisness logic which takes 5 minutes

*/

Commit
Run Code Online (Sandbox Code Playgroud)

打开另一个sql会话并运行以下查询

Begin Transaction
Update Transactions
Set = ...
where ....
commit
Run Code Online (Sandbox Code Playgroud)