【问题标题】:What kind of lock is placed for SELECT statement within a transaction in SQL ServerSQL Server 事务中的 SELECT 语句放置什么样的锁
【发布时间】:2016-06-13 02:54:13
【问题描述】:

我相信 SQL Server 中的每个SELECT 语句都会导致放置共享锁或键锁。但是它在事务中会放置相同类型的锁吗? Shared 或 Key 锁是否允许其他进程读取相同的记录?

例如我有以下逻辑

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 语句移到事务之外并仅将插入/更新保留在一个事务中?

【问题讨论】:

    标签: sql sql-server transactions database-deadlocks locks


    【解决方案1】:

    SELECT 将始终放置共享锁 - 除非您使用 WITH (NOLOCK) 提示(然后 不会放置锁),否则请使用 READ UNCOMMITTED 事务隔离级别(同样的事情) ,或者除非您使用 WITH (XLOCK)WITH (UPDLOCK) 等查询提示专门覆盖它。

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

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

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

    【讨论】:

    • 非常感谢您提供这些宝贵的信息。因此,如果 SQL Server 默认使用 Read Committed 任何选择语句。自从尝试在事务之外分离我的 SELECT 查询之后就没有了
    • @MikeA:不,没有任何区别 - 共享锁将被非常短暂地获取以实际读取数据(只是为了防止另一个进程更改它们当您阅读它们时),然后它们将再次被释放 - 在该事务内部或外部 - 相同的过程
    • 如果您不知道这一点:READ COMMITTED 选择并不总是锁定。仅对未提交更改的页面进行锁定。您可以在 RC 下读取已被 XLOCK、TABLOCK'ed 由另一个事务处理的表。 (我试过了。)
    • 当使用READ COMMITTED SNAPSHOTSNAPSHOT 隔离级别时SELECT 语句不请求共享锁。
    猜你喜欢
    • 2019-09-08
    • 2017-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    • 2016-10-30
    • 2017-03-11
    相关资源
    最近更新 更多