SQL锁机制

根据锁的粒度,SQL锁主要分为表级锁、行级锁和页级锁。表级锁,顾名思义,直接锁住整张表。当某个会话对表进行写操作时,会先获得写锁,此时其他会话的所有操作都会被阻塞,直到锁被释放。这种锁开销小、加锁快,但并发能力较差,在MyISAM存储引擎中比较常见。行级锁则精细得多,它只锁定需要操作的那些数据行,其他行仍然可以正常访问。这在并发写操作频繁的场景下优势明显,但管理开销较大。InnoDB存储引擎支持行级锁,这也是它比MyISAM更适合高并发环境的重要原因。页级锁算是折中方案,锁定数据页(通常为4KB或8KB),粒度介于表锁和行锁之间。

从锁的模式来看,可以分为共享锁(S锁)和排他锁(X锁)。共享锁允许多个会话同时读取同一资源,但任何会话都不能修改------简单说就是"能读不能写"。排他锁则霸道得多,一个会话对资源加了排他锁后,其他会话既不能读也不能写,必须等待锁释放。这两种锁的兼容关系很简单:共享锁之间可以共存,但共享锁与排他锁、排他锁与排他锁之间互斥。

除了基本锁类型,还有意向锁这种机制。意向共享锁(IS)和意向排他锁(IX)是表级锁,它们的主要作用是"声明意图"。比如某个会话要对某些行加排他锁前,会先在表级别加一个意向排他锁。这样当另一个会话想要给整张表加锁时,通过检查意向锁就能快速知道表中是否有行被锁定,而不需要逐行检查,大大提升了效率。

说到锁就不得不提数据库的隔离级别。读未提交(Read Uncommitted)基本不加锁,可能读到别人未提交的数据;读已提交(Read Committed)通过加锁避免脏读,但可能出现不可重复读;可重复读(Repeatable Read)通过间隙锁等机制防止幻读;串行化(Serializable)则对所有读取都加锁,完全保证隔离性。以MySQL的InnoDB为例,在可重复读级别下,不仅会对现有数据行加锁,还会通过间隙锁锁定不存在的键值范围,有效防止其他事务在范围内插入新数据。

更新锁(U锁)是SQL Server中的特殊锁类型,它在更新操作初期使用。当需要先查找再更新时,更新锁可以防止多个会话同时查询数据后都试图更新,从而避免死锁。在找到需要更新的数据后,更新锁会升级为排他锁。

实际开发中,死锁是令人头疼的问题。两个会话各自持有对方需要的锁,又都在等待对方释放,形成无限等待。比如事务A先锁定了表T1,请求T2;同时事务B锁定了表T2,请求T1------典型的死锁场景。数据库通常有死锁检测和解除机制,会选择一个事务作为"牺牲者"回滚,让另一个继续执行。

合理使用锁需要结合业务场景。在查询语句中,可以通过SELECT ... FOR UPDATE对读取的行加排他锁,防止其他会话修改;或者使用SELECT ... LOCK IN SHARE MODE加共享锁。设置锁等待超时时间也是常用技巧,避免长时间阻塞。另外,尽量让事务简短,按相同顺序访问表资源,都能有效减少锁冲突。

锁机制是数据库并发控制的基石,理解不同锁的特性和适用场景,对设计高并发、高可用的系统至关重要。作为开发者,我们需要在数据安全性和系统性能间找到平衡点,让锁成为保障数据安全的利器,而不是系统性能的瓶颈。

相关推荐
笃行3505 小时前
能跑不等于正确:生产环境不规范 SQL 的隐藏风险与编码规范
数据库
龙虾PRO5 小时前
能源与股票量化核心差异,AI全链路落地实操手册
java·面试·职场和发展
llwszx5 小时前
【Java/Go后端手撸原生Agent(第九篇):Plan-and-Execute规划模式——从“走一步看一步“到“先谋后动“】
java·python·golang·agent开发·plan模式·规划执行模式
ZJH__GO5 小时前
网络编程v2--多客户端互通
java·运维·服务器·开发语言·计算机网络
霸道流氓气质5 小时前
SpringBoot中基于 AES-GCM + KMS 密钥管理的数据加解密 Starter 实践
java·数据库·spring boot
Gofarlic_OMS6 小时前
NX浮动许可调度黑名单机制,对比两款谁更合理
java·大数据·运维·开源·制造
三言老师6 小时前
CentOS7.9:Redis服务器部署结构化实战教程
linux·运维·服务器·数据库
乐观的Terry6 小时前
8、发布系统-完整流水线的核心
java·spring boot·spring·spring cloud
Alexalbb6 小时前
从角色过滤到可审计授权:单体系统数据权限设计复盘与演进
java
番茄炒鸡蛋加糖6 小时前
MySQL 实战调优& 分表基础
数据库·mysql