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加共享锁。设置锁等待超时时间也是常用技巧,避免长时间阻塞。另外,尽量让事务简短,按相同顺序访问表资源,都能有效减少锁冲突。

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

相关推荐
小羊没烦恼!2 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里2 天前
java中的继承和多态的区别
java
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕2 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码2 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖2 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时2 天前
01-06-A-JVM排查实战详解
java·jvm
这个DBA有点耶2 天前
MVCC深入:Read View、版本链与快照读——InnoDB并发控制的内核
数据库·mysql·架构
vipxieliang2 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
DBA_G2 天前
从地面到云霄:GBase数据库在民航三大场景的落地实践
数据库