数据库锁的初衷是处理并发问题,当并发出现时,数据库要合理的控制资源的访问规则,而锁就是用来实现这些访问规则的数据结构。
mysql里面的锁大致可以分为 全局锁、表锁、行锁。
全局锁
就是对整个数据库实例加锁 ,mysql提供了一种加全局锁的方法,命令是 flush tables with read lock 该命令会让整个数据库处于只读状态。之后其他线程的更新语句,更改表结构语句 全部会被堵塞。当客户端连接断开时,数据库会恢复可读写状态,或者执行 unlock tables 主动释放锁。
表级锁
分为表锁和元数据(MDL)锁
表锁的语法是 lock tables … read/write。在还没有出现更细粒度的锁的时候,表锁是最常用的处理并发的方式。而对于 InnoDB 这种支持行锁的引擎,一般不使用 lock tables 命令来控制并发,毕竟锁住整个表的影响面还是太大。
MDL锁 不需要显示调用,在访问一个表的时候回被自动加上,在 MySQL 5.5 版本中引入了 MDL,当对一个表做增删改查操作(DML)的时候,加 MDL 读锁;当要对表做结构变更操作(DDL)的时候,加 MDL 写锁。
- 读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。
- 读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。
对数据量小但请求频繁的表修改表结构也要注意,若有MDL读锁不释放,修改表结构,会阻塞后续大量的增删改查语句。导致数据库线程池爆满。
行锁
是存储引擎层实现的,并不是所有引擎都支持行锁,MyISAM引擎就不支持行锁,这意味同一张表在任意时刻只能有一个更新在执行。这会严重影响业务的并发度。InnoDb是支持行锁的。
行锁顾名思义 在同一时刻,对于同一行数据的更新,只能一个一个的执行。
在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
所以如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。