试图完全理解SQL Server的隔离级别-尤其是REPEATABLE READ。
我有一个存储过程,它启动一个事务并在一些数据周围放置一个光标(嘘声)。这可以是相当大块的数据,所以可能需要一段时间才能完成。
然后它将提交或回滚。
在此期间,在事务关闭之前,如果有人调用导致读取其中一些受影响行的方法,我的理解是该方法将停滞,直到第一个方法完成。然后他们将获得数据(只要没有超时发生)
我认为我是对的,但问题是-我是吗?
试图完全理解SQL Server的隔离级别-尤其是REPEATABLE READ。
我有一个存储过程,它启动一个事务并在一些数据周围放置一个光标(嘘声)。这可以是相当大块的数据,所以可能需要一段时间才能完成。
然后它将提交或回滚。
在此期间,在事务关闭之前,如果有人调用导致读取其中一些受影响行的方法,我的理解是该方法将停滞,直到第一个方法完成。然后他们将获得数据(只要没有超时发生)
我认为我是对的,但问题是-我是吗?
REPEATABLE READ
会防止 SELECT
语句在事务结束之前解除共享锁。
使用事务 1
的隔离级别为 READ COMMITTED
,你可以在事务 1
中选择一行并在事务 2
中更新它。
使用事务 1
的隔离级别为 REPEATABLE READ
,你不能在事务 2
中更新在事务 1
中选择的同一行。
场景:
1 SELECT -- places a shared lock and immediately lifts it.
2 UPDATE -- places an exclusive lock. Succeeds.
1 SELECT -- tries to place a shared lock but it conflicts with the exclusive lock placed by 2. Locks.
1 SELECT -- places a shared lock and keeps it
2 UPDATE -- tries to places an exclusive lock but it's not compatible with the shared lock. Locks
1 SELECT -- the lock is already placed. Succeeds.
更新:
关于你的问题:在SQL Server
中,即使使用 REPEATABLE READ
,SELECT
语句也不会相互锁定,因为它们放置的共享锁是兼容的。
CREATE TABLE t_lock (id INT NOT NULL PRIMARY KEY, value INT NOT NULL)
INSERT
INTO t_lock
VALUES (1, 1)
-- Session 1
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
BEGIN TRANSACTION
DECLARE @id INT
DECLARE cr_lock CURSOR DYNAMIC
FOR
SELECT id
FROM t_lock
OPEN cr_lock
FETCH cr_lock
id
--
1
-- Session 2
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
BEGIN TRANSACTION
DECLARE @id INT
DECLARE cr_lock CURSOR DYNAMIC
FOR
SELECT id
FROM t_lock
OPEN cr_lock
FETCH cr_lock
id
--
1
-- Session 1
DEALLOCATE cr_lock
COMMIT
-- Session 2
DEALLOCATE cr_lock
COMMIT
SELECT
放置一个S
锁,并将其升级为U
,然后再使用UPDATE
升级为X
。第二个事务将尝试放置一个S
锁,但会失败并被锁定。第一个事务提交,第二个事务接收到锁并看到更新的记录。 - Quassnoi正确。
来自MSDN的完整描述:
指定语句不能读取其他事务已修改但尚未提交的数据,也不能修改当前事务已读取的数据,直到当前事务完成。
在事务中由每个语句读取的所有数据上放置共享锁,并且这些锁将一直保持到事务完成。这可以防止其他事务修改当前事务已读取的任何行。其他事务可以插入与当前事务发出的语句匹配的新行。如果当前事务重试该语句,则会检索到新行,从而导致幻读。由于共享锁保持到事务结束而不是在每个语句结束时释放,因此并发性低于默认的READ COMMITTED隔离级别。仅在必要时使用此选项。
SELECTs
,没有UPDATEs
)是“不正确”的 :), 两个选择都不会相互锁定,无论是使用RC
还是RR
。 - Quassnoi