MySQL中的锁
“数据库中锁的设计初衷是处理并发问题。”
全局锁
锁住整个数据库,防止一切并发修改,但是可以读。全局锁的作用是,用来进行数据库备份的时候,防止并发修改。
如果不使用全局锁的话,在InnoDB存储引擎中,RR隔离级别下,利用MVCC,可以实现“不停机”备份(即备份数据的同时,数据库还能写入数据)。站在备份的角度上看,但是这种方式,与全局锁备份的效果一样。
除了使用全局锁,还能设置数据库为只读,但是这种方式的缺陷是,第一个是当客户端故障的时候,数据库仍然是只读,而全局锁会释放;第二个事,数据库只读在主从集群中有其他语意。
表级锁
表级锁分为表锁和元数据锁,锁住的是整张表。
表锁,有读锁和写锁之分,表锁除了会限制其他线程的操作,也会限制本线程的操作,例如线程A获取了表t1的读锁,t2的写锁,那么其他线程写t1会阻塞,读写t2会阻塞,线程A只能读t1不能写t1,可以读写t2。
元数据锁,不需要手动加,会自动加上。当线程A对数据表进行增删改查操作的时候,线程A会获取元数据读锁,数据表结构的操作就会被阻塞。当线程A对数据表的结构进行修改的时候,会加上元数据写锁,数据表的增删改查操作都会阻塞。
行锁
行锁,针对的是一行数据。行锁需要讨论的是对性能的影响。行锁是需要的时候,才会获取,但是只有当事务提交的时候,才会释放,否则会一直占用。由此引发两个性能提升的点。
当一个事务中,需要锁住多行的时候,应该尽量把锁冲突高、最可能影响并发度的行锁放到后面。
死锁问题,当事务A和事务B,事务A占有行锁1,事务B占有行锁2,然后事务A申请行锁2,事务B申请行锁1,形成死锁,导致数据库连接无效消耗CPU资源。解决方案,InnoDB引擎默认提供了获取锁超时时间参数和开启死锁监测参数。这两种方案都能解决一定程度上的死锁问题,但是锁超时时间难以衡量,死锁监测对于数据库连接多的时候,时间复杂度太高。引出第三种方案,将一行改成逻辑上的多行,例如这样的话,原先并发修改竞争的一个资源,现在竞争多个资源,可以减少冲突的概率。