在SQL Server中的事务中,对于SELECT语句使用的是共享锁。

6
我相信在SQL Server中,每个SELECT语句都会导致共享锁或键锁的放置。但是,在事务中执行时,它是否会放置相同类型的锁?共享锁或键锁是否允许其他进程读取相同的记录?
例如,我有以下逻辑:
Begin Trans
-- select data that is needed for the next 2 statements
SELECT * FROM table1 where id = 1000; -- Assuming this returns 10, 20, 30

insert data that was read from the first query
INSERT INTO table2 (a,b,c) VALUES(10, 20, 30);

-- update table 3 with data found in the first query
UPDATE table3
SET d = 10,
   e = 20,
   f = 30;

COMMIT;

在这种情况下,我的select语句是否仍会创建共享锁或键锁,还是会升级为独占锁?其他事务能否从table1中读取记录,还是所有事务都要等到我的事务提交后才能从中选择?

在应用程序中,将select语句移出事务并只保留插入/更新操作是否有意义?

1个回答

10

SELECT会始终放置一个共享锁 - 除非使用WITH (NOLOCK)提示(然后不会放置任何锁定),使用READ UNCOMMITTED事务隔离级别(同样的效果),或者使用查询提示明确覆盖它,例如WITH (XLOCK)WITH (UPDLOCK)

共享锁允许其他读取进程也获取共享锁并读取数据 - 但它们防止获得排他锁(用于插入、删除、更新操作)。

在这种情况下,只选择了三行,就不会有锁升级(只有在单个事务获取超过5000个锁时才会发生)。

根据事务隔离级别的不同,这些共享锁将被保持不同的时间。在默认级别READ COMMITTED中,数据读取后锁定立即释放,而在REPEATABLE READSERIALIZABLE级别中,锁定将一直保持到事务提交或回滚。


非常感谢您提供这么有价值的信息。因此,如果SQL Server默认使用“读取已提交”来执行任何选择语句,则没有必要尝试将我的SELECT查询从事务中分离出来。 - Junior
@MikeA:不,没有任何区别——共享锁只会在实际读取数据时短暂地获取(仅为了防止另一个进程在您读取它们时更改它们),然后它们将被释放——无论是在事务内部还是外部——同一进程。 - marc_s
如果您还不知道:READ COMMITTED 选择不总是锁定。仅在具有未提交更改的页面上才会获取锁定。您可以在另一个事务通过 XLOCK、TABLOCK 锁定的情况下,在 RC 下读取表格。(我试过了。) - usr
1
当使用READ COMMITTED SNAPSHOTSNAPSHOT隔离级别时,SELECT语句不会请求共享锁。 - Jesús López

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接