说说DB2里那些锁到底是啥属性和怎么影响性能的
- 问答
- 2026-01-16 01:01:50
- 1
综合整理自IBM官方文档《DB2锁和并发指南》、Oracle社区DB2版块资深用户讨论帖“深入理解DB2锁机制”、数据库专家Craig S. Mullins的著作《DB2开发者指南》以及IBM技术支持案例库中的常见性能问题分析)
DB2里的锁,说白了就是数据库用来防止大家同时改同一份数据时把数据搞乱的一种“交通警察”机制,想象一下,如果一条路没有红绿灯,所有车都想同时过,肯定就撞上了,数据库里的数据就是这条路,而锁就是红绿灯,它告诉各个程序什么时候可以“走”(读或写),什么时候必须“停”(等待)。
这些锁有几个关键属性,直接决定了它们是怎么工作的,以及会不会堵车。
第一个属性是锁的类型,这是最重要的,DB2里有好几种常见的锁,强度不一样。
- 共享锁(S锁):就像好几个人同时看同一本书,谁都可以读,但不能有一个人在书上乱涂乱画,当一个程序只是查询数据时,DB2通常会给它加个S锁,多个程序可以同时持有同一个数据上的S锁,相安无事,这对应的是“读”操作。
- 排他锁(X锁):这就好比你把书借回家,在上面写读书笔记,这时候书在你手里,别人既不能看(不能读),更不能抢走去修改(不能写),当一个程序要修改数据(比如UPDATE、DELETE)时,DB2就会给它加X锁,一个数据上一旦有了X锁,其他程序就不能再获得任何类型的锁(无论是S锁还是X锁),只能干等着,这是最“霸道”的一种锁。
- 更新锁(U锁):这是一种“预备”状态的锁,比如一个程序说“我可能要修改这行数据,但得先看看值是什么再决定”,DB2就会给它加个U锁,U锁和S锁是兼容的,也就是说,允许其他人也来读,一旦这个程序决定真的要改了,U锁就会立刻升级为更强硬的X锁,这时候其他所有的读操作都会被挡住,U锁的存在是为了防止一种叫“死锁”的尴尬情况(后面会说到)。
第二个属性是锁的粒度,也就是锁的范围有多大,DB2不会傻到把整张表都锁住,那样效率太低了,它会根据情况锁不同大小的范围:
- 行锁:最细的粒度,只锁住你要操作的那一行,这是并发性最好的方式,好比只封锁一个停车位,不影响其他车位停车。
- 页锁:锁住存放那一行数据的整个“数据页”(一个页里可能有多行数据),如果你的操作不小心波及了同一页上的其他行,DB2可能会为了省事,直接锁住整页。
- 表锁:最粗的粒度,直接把整张表锁住,这就像把整个停车场都封了,影响巨大,通常在执行一些需要扫描全表的操作,或者你明确用
LOCK TABLE语句时才会发生。
DB2会尽量使用最细的锁(比如行锁)来保证高并发,但有时候它也会“锁升级”,比如你的事务又臭又长,一口气对同一张表里成千上万行加了锁,DB2觉得管理这么多小锁太累了、太占内存了,就会“啪”一下,把所有这些行锁合并成一个表锁,这对其他想访问这张表的人来说就是一场灾难。
第三个属性是锁的持续时间,也就是锁会hold多久,这跟你的事务密切相关,一个锁通常会从它被加上开始,一直持续到事务结束(无论是提交还是回滚)才释放。一个性能杀手就是:长时间不提交的事务,你的事务开着不结束,你持有的所有X锁就都不会放,后面排队的人就得一直等。
这些锁是怎么影响性能的呢?
影响性能的核心就两个字:等待。
-
直接性能下降:这是最直接的,当程序A持有一个数据的X锁正在修改,程序B想读这个数据(申请S锁)或者程序C也想修改(申请X锁),那么B和C就会被DB2强行拦住,进入“锁等待”状态,它们什么也干不了,CPU闲着,但响应时间却飞速上涨,在DB2的快照监控里,你会看到
Lock waits、Lock wait time这些指标特别高。 -
并发度降低:锁的粒度越粗,并发度越低,如果你的应用设计或SQL写法不当,导致DB2经常使用页锁甚至触发锁升级成表锁,那么即使大家操作的不是同一行数据,也会被互相阻塞,好比你想停1号车位,但因为整个停车场被锁了,你也进不去。
-
最糟糕的情况:死锁:死锁是性能的“癌症”,比如程序A锁住了行1,同时程序B锁住了行2,然后程序A想去锁行2,程序B想去锁行1,结果就是:A在等B释放行2,B在等A释放行1,俩人互相瞪眼,永远等下去,DB2有个后台进程叫“死锁检测器”,它会定期检查这种僵局,一旦发现,就会“牺牲”掉其中一个事务(通常回滚修改量最小的那个),让它报错退出,从而解开死锁让另一个继续,但对被选中的那个事务和用户来说,体验极差,操作白做了还得重试。
-
如何避免和缓解? 根据IBM技术支持案例库的总结,常见思路是:
- Commit Often(频繁提交):让事务尽可能短小精悍,干完活立刻提交,快速释放锁,别在一个事务里做太多事。
- Access Data in Same Order(按相同顺序访问数据):如果所有程序都约定好,先更新A表再更新B表,就能极大降低死锁概率。
- 用对的隔离级别:DB2有像“读稳定性”、“游标稳定性”、“未提交读”等隔离级别,未提交读”允许你读别人还没提交的数据(脏读),但它根本不会申请S锁,所以永远不会被X锁阻塞,这在一些允许读到中间状态、追求极高查询速度的场景下很有用,但这是一把双刃剑,用错了会导致数据不一致。
- 优化SQL和索引:让你的查询通过索引快速定位到需要的几行数据,而不是全表扫描,全表扫描更容易引发锁升级。
DB2的锁是个必不可少的“坏东西”,没有它数据会乱,但用不好就会成为性能瓶颈,理解它的基本属性和工作原理,目的不是为了去手动调锁,而是为了在设计和编写应用程序时,能有一种“锁意识”,主动避免那些容易引发严重锁冲突的代码模式。

本文由水靖荷于2026-01-16发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/81489.html
