我试图了解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)
现在从msdn我明白了
当激活select时,共享锁被占用,因此没有其他事务可以修改数据(避免脏读)。文档还讨论了行级,页级,表级锁。我想到了关注scenarion
Begin Transaction
select * from Transactions
/*
some buisness logic which takes 5 minutes
*/
Commit
我想了解的是获取共享锁的持续时间以及(行,页,表)。(/ p>
只有在语句select * from Transactions
运行时才会获取锁定,或者在我们达到COMMIT之前将整个5分钟获取锁定。
答案 0 :(得分:20)
您提出错误的问题,您担心实施的详细信息。您应该考虑和关注的是隔离级别的语义。 Kendra Little有一张漂亮的海报解释他们:Free Poster! Guide to SQL Server Isolation Levels。
你的问题应改写如下:
问:我会看到什么项目?从项目中选择*
问:如果有未提交的事务已插入/删除/更新项目会发生什么? 答:您的SELECT将阻塞,直到所有未提交的项目都已提交(或回滚)。
问:如果在上面运行上述查询时插入/删除/更新新项目会怎么样?
答:结果尚未确定。您可能会看到一些修改,不会看到其他一些修改,并且可能阻塞它们中的一些修改。
READ COMMITTED在您的陈述完成后不作出承诺,与交易的长度无关。如果再次运行该语句,您将再次具有与之前状态完全相同的语义,并且您之前看到的项目可能会更改,消失并且可能会出现新项目。显然,这意味着在您选择后可以>>对项目进行更改。
更高的隔离级别提供更强的保证:REPEATABLE READ保证在您提交之前不会修改或删除您第一次选择的项目。 SERIALIZABLE增加了保证,在您提交之前,第二个选择中不会出现任何新项目。
这是您需要了解的,没有实现机制的工作原理。掌握了这些概念后,您可以询问实施细节。它们都在Transaction Processing: Concepts and Techniques中描述。
答案 1 :(得分:11)
你的问题很好。了解获取哪种锁可以深入理解DBMS。在SQL Server中,在所有隔离级别下(Read Uncommitted,Read Committed(默认),Repeatable Reads,Serializable)为Write操作获取独占锁。
无论隔离级别如何,当事务结束时都会释放独占锁。
隔离级别之间的差异是指获取/释放共享(读取)锁定的方式。
在Read Uncommitted隔离级别下,不会获取共享锁。在此隔离级别下,可以发生称为“Dirty Reads”的并发问题(允许事务从已被另一个正在运行的事务修改但尚未提交的行中读取数据,因此可以回滚)。
在Read Committed隔离级别下,为相关记录获取共享锁。当前指令结束时释放共享锁。此隔离级别可防止“脏读”,但由于记录可由其他并发事务更新,因此“不可重复读取”(事务A检索行,事务B随后更新行,事务A稍后再次检索同一行) 。事务A检索同一行两次,但看到不同的数据)或“幻像读取”(在事务过程中,执行两个相同的查询,第二个查询返回的行集合与第一个不同)可能发生
在“可重复读取”隔离级别下,将为事务持续时间获取共享锁。防止“脏读”和“不可重复读”,但仍可能出现“幻读”。
在Serializable隔离级别下,将为事务持续时间获取范围内的共享锁。上述并发问题均未发生,但性能大幅降低,存在死锁发生的风险。
答案 2 :(得分:6)
锁只会在select * from Transaction
运行时获取
您可以使用以下代码进行检查
打开一个sql会话并运行此查询
Begin Transaction
select * from Transactions
WAITFOR DELAY '00:05'
/*
some buisness logic which takes 5 minutes
*/
Commit
打开另一个sql会话并运行查询
Begin Transaction
Update Transactions
Set = ...
where ....
commit
答案 3 :(得分:0)
首先,锁定仅在语句运行时获取。 您的声明分为两部分,假设很简单:
select * from Transactions
update Transactions set amt = xxx where Tid = xxx
何时/在READ COMMITTED隔离级别中保留/释放什么锁?
select * from Transactions
运行时,没有获得锁。
在update Transactions set amt = xxx where Tid = xxx
之后,将添加X锁用于更新/更新密钥,为页面/标签添加IX锁
所有锁定仅在提交/回滚后释放。这意味着在运行中不会释放任何锁。