MySQL系列3 - 全局锁表锁行锁
Posted 栋总侃技术
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL系列3 - 全局锁表锁行锁相关的知识,希望对你有一定的参考价值。
全局锁
对整个库进行加锁的操作。此时,整个数据库只有读权限,一般只在对整库进行备份的时候使用全局锁。命令是:
Flush tables with read lock;
在客户端断开会自动释放,不用担心客户端连接断开了,锁一直都没法释放。
如果数据库是只读状态,这个时候所有的insert、update操作都是停摆状态,必定会影响业务逻辑。(在主库上加锁无法insert、update,在从库上加锁影响binlog的同步)
全局锁虽然影响大,但是很有必要的。假设一个购买过程如下 :
扣除该用户的余额
扣除商品的库存
生成一个订单记录
这三步分别是对三个表的操作,如果在数据备份的时候不使用全局锁,而使用表锁,那么备份库的数据很可能出现不一致。
表锁
有两种类型的表锁,一种是通过命令显示调用 (同样在客户端断开会自动释放)
// table_a 加上读锁
// table_b 加上写锁
lock tables table_a read, table_b write;
另一种是 MDL(metadata lock)。不需要显示使用,为了保证读写正确性自动加上的锁。
例如一个线程正在查询某张表的数据时,另一个线程正在该表上增加/删除一个字段,或者增加索引,那么此时查询线程拿到的结果表结构是对应不上的。
MDL有读锁和写锁
1. 读锁之间是不互斥的,a线程读和b线程读之间不影响。
2. 读写锁之间是互斥的,参考上面的例子。
3. 写锁之间也是互斥的,假设两个线程都在变更表结构。
所以,我们在对线上的表结构做变更、增加索引等操作时,是要获取该表的MDL写锁的,避免影响线上业务,建议在业务相对不繁忙时操作。
行锁
不同于全局锁和表锁,行锁是引擎层实现的。MyISAM存储引擎不支持行锁,innoDB存储引擎支持行锁。(这也是innoDB可以取代MyISAM的原因之一)
我们来看下下面这个场景:
在时刻2 session2会怎样呢?
在知道有行锁的存在之后,很容易得出结论在时刻2 session2会被阻塞。那么问题又来了,session2的update语句在什么时候才会执行呢?
答案是在时刻3 session1 commit之后才会执行,并不是在时刻2 session1执行完update语句后。
在 InnoDB 事务中,行锁是在需要的时候才加上的,在事务结束时才释放。这就是两阶段锁协议。
我们要特别注意:InnoDB 事务中,行锁在事务结束时才释放而不是语句执行完就释放。那么我们再回过头看下之前的一个购买流程的例子:
扣除该用户的余额
扣除商品的库存
生成一个订单记录
那么这三条语句在一个事务中的执行顺序你会怎么安排呢?
答案应该是:3,1,2。
如果多个用户购买同一个商品,就会在第2步在扣除商品库存时,对这个商品这一行数据产生行锁,而行锁在事务提交后才释放。这样可以最大的缩短行锁存在的时间,从而提高并发量。当然,步骤1该用户账号同时购买商品,也可能存在行锁,这种概率比2小得多。
往期回顾:
以上是关于MySQL系列3 - 全局锁表锁行锁的主要内容,如果未能解决你的问题,请参考以下文章