18

我正在尝试了解 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我明白了

当触发选择时,将采用共享锁,因此没有其他事务可以修改数据(避免脏读)。文档还讨论了行级、页级、表级锁。我想到了以下场景

Begin Transaction

select * from Transactions

/*
some buisness logic which takes 5 minutes

*/

Commit

我想了解的是获取共享锁的持续时间以及哪个(行、页、表)。

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

4

4 回答 4

24

您问错了问题,您担心实施细节。您应该考虑和关心的是隔离级别的语义。Kendra Little 有一张很好的海报来解释它们:免费海报!SQL Server 隔离级别指南

你的问题应该改写为:

从项目中选择 *

问:我会看到哪些项目?
A:所有承诺的项目

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

问:如果我运行上面的查询时插入/删除/更新新项目会发生什么?
A:结果未定。您可能会看到一些修改,不会看到其他一些修改,并且可能会阻塞,直到其中一些提交。

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

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

这是你需要了解的,而不是实现机制是如何工作的。在你掌握了这些概念之后,你可能会询问实现细节。它们都在事务处理:概念和技术中进行了描述。

于 2012-07-04T14:23:45.087 回答
20

你的问题很好。了解获取什么样的锁有助于深入了解 DBMS。在 SQL Server 中,在所有隔离级别(未提交读、已提交读(默认)、可重复读、可序列化)下,都会为写操作获取排他锁。

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

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

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

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

在可重复读取隔离级别下,在事务持续时间内获取共享锁。“脏读”和“不可重复读”被阻止,但“幻读”仍然可能发生。

在可序列化隔离级别下,在事务期间获取范围共享锁。上述并发问题均未发生,但性能大大降低,并且存在发生死锁的风险。

于 2016-05-31T11:03:53.160 回答
7

锁只会在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
于 2012-07-04T11:56:59.797 回答
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 锁

所有锁只有在提交/回滚后才会释放。这意味着在 trans 运行中不会释放任何锁。

于 2018-08-17T10:51:26.967 回答