SQL Server里各种资源锁到底是咋回事,搞懂这些锁模式才能不慌
- 问答
- 2026-01-18 13:43:30
- 3
主要综合整理自微软官方文档“Lock Modes in the Database Engine”、SQL Server Central社区的技术讨论以及《Microsoft SQL Server Internals》一书中的相关章节)
很多人一听到数据库“锁”就觉得头疼,觉得这东西特别复杂,容易出问题,比如经常遇到的阻塞(blocking)或者死锁(deadlock),但其实,锁是SQL Server用来保证我们数据“没错”的基石,你可以把它想象成一个非常负责任的图书馆管理员,想象一下,如果图书馆里有一本非常热门的书,如果大家随便拿随便改,那最后谁也不知道这本书的原文是啥了,管理员的作用就是给这本书加上各种规则:比如你可以读,但不能在书上写字(共享锁);或者你申请了要修改这本书,那在你修改的时候,别人既不能读也不能动(排他锁),SQL Server里的锁就是这个道理,只不过管理的是数据页、行、表这些资源。
SQL Server到底有哪些常见的“锁模式”呢?咱们一个一个来说,不用怕那些英文缩写。

最基本、最常用的两种锁:共享锁(Shared Lock,简称S锁) 和排他锁(Exclusive Lock,简称X锁)。
共享锁,顾名思义,是大家能一起共享的锁,当你执行一个普通的SELECT查询时,SQL Server默认会给你要读取的数据加上共享锁,这就像很多人可以同时读同一本书,互不干扰,多个用户可以同时持有同一块数据上的共享锁,共享锁的核心原则是:它和其他的共享锁是兼容的,但它绝对不允许有排他锁存在,也就是说,只要有人在读这块数据,你就不能去修改它(因为修改需要排他锁),这是为了保证读的时候数据不会变。
排他锁,就和它的名字一样“排他”,非常霸道,当你执行INSERT(插入)、UPDATE(更新)、DELETE(删除)这些会改变数据的操作时,SQL Server就会给受影响的数据加上排他锁,一个资源(比如一行数据)上,在同一时间只能有一个排他锁存在,这个排他锁一旦加上,其他任何类型的锁(不管是别的排他锁还是共享锁)都不能再加到这个资源上,这就好比有个人把书拿到小房间里去重写了,在他写完出来之前,任何人都不能进去读或者写这本书。

事情没那么绝对,你想修改一批数据,但你又不想让别人在你修改的同时来读这些数据,导致别人看到你改到一半的、不完整的数据,但同时,你又希望允许别人去读你还没有修改到的其他数据,这时候,就需要一种不那么霸道的“写锁”,这就是更新锁(Update Lock,简称U锁)。
更新锁可以看作是一个“预备排他锁”,它通常用在UPDATE操作的初始阶段,SQL Server需要先找到要更新的那些数据行,在查找过程中,它会先给这些行加上更新锁,更新锁的魅力在于:它和共享锁是兼容的,也就是说,在它还是更新锁的时候,其他人依然可以来读这些数据,一个资源上只能有一个更新锁,这样就能防止“死锁”的一种常见情况:即两个人都想更新,都先加了共享锁,然后都想把共享锁升级成排他锁,结果互相等待,卡死了,当SQL Server真正要开始修改数据的那一刻,它会把更新锁升级为排他锁,这时候其他所有的读写操作就必须等待了。
接下来是意向锁(Intent Locks),这是最容易让人迷惑的锁,但其实是为了提高效率而存在的,SQL Server的锁可以在不同的层级上设置,比如行级、页级、表级,意向锁就是一种“信号灯”,它被用在更高的层级上(比如表级),用来表明其下层级的某个资源已经被上锁了。

意向锁也分好几种,比如意向共享锁(IS)、意向排他锁(IX)、意向排他共享锁(SIX)等等,举个例子就明白了:假设一个事务在表里的某一行上持有一个排他锁(X锁),如果没有意向锁机制,当另一个事务想给整个表加一个排他锁(比如执行DROP TABLE)时,它必须疯狂地去检查这个表的每一行、每一页,看看有没有锁,这效率太低了,而有了意向锁机制,那个在行上加了X锁的事务,会同时在表级别加一个意向排他锁(IX),这样,后来那个想给表加X锁的事务,只需要看一眼表级别,发现已经有一个IX锁了,它就立刻知道“这个表里已经有被锁住的行了,我不能加表锁”,于是它就直接等待,省去了扫描所有底层资源的巨大开销,意向锁就是一种高效的“此处已有锁,的告示牌。
除了这些,还有一些特殊场景下的锁,比如架构锁(Sch-M和Sch-S),当你修改表结构(比如增加一个列)时,需要加架构修改锁(Sch-M),这个锁会阻塞所有其他的连接访问该表,而当你编译一个查询时,会加架构稳定性锁(Sch-S),这个锁允许其他连接也加Sch-S锁(大家一起编译查询没问题),但会阻止任何Sch-M锁(不能边编译边改表结构)。
还有键范围锁(Range Lock),这主要是在可序列化(SERIALIZABLE)隔离级别下,为了防止“幻读”而出现的,它锁的不是一个具体的记录,而是一个范围,确保在这个范围内不能插入新的满足条件的记录。
批量更新锁(BU锁)是在进行大容量数据导入时,为了在并发和速度之间取得平衡而使用的一种特殊锁模式。
理解了这些锁的模式和它们之间的兼容关系(比如谁和谁可以同时存在,谁和谁不能共存),你再看数据库的阻塞问题,思路就会清晰很多,当一个查询变慢时,你可以通过系统视图(比如sys.dm_tran_locks)去查看当前有哪些锁,是什么模式,在等待什么资源,从而找到问题的根源,锁不是敌人,而是维护数据一致性的盟友,搞懂它,你才能在数据库出现性能问题时真正做到心里不慌。
本文由钊智敏于2026-01-18发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/83067.html
