全局锁
场景:
做全库逻辑备份。
使用:
- Flush tables with read lock ,让数据库处于只读的状态,其他的线程的更新、建库改表的语句被阻塞(对于不支持事务的存储引擎:MyISAM等)
- 使用mysqldump逻辑备份工具设置参数-single-transaction参数,会开启一个事务,来确保拿到一致性视图。由于MVCC的支持,这个过程数据可以正常更新。(支持事务的存储引擎:InnoDB等)
补充:
- DML:增删改数据
- DDL:加字段等修改表结构的操作
表级锁
表锁:
- 共享锁(读锁):不会限制线程读,会限制线程写(所说的线程包含:自身线程以及其他线程)。
- 独占锁(写锁):不会限制本线程的读写,会限制其他线程读写。
- 加锁:lock tables 表名 read、write
- 释放:unlock tables 主动释放锁、或者客户端断开的时候自动释放。
意向锁
作用:为了快速判断表里是否有记录被加锁;
- 意向共享锁:在InnoDB引擎的表里对某些记录加上共享锁之前,需要先在表级别加上一个意向共享锁;
- 意向独占锁:在InnoDB引擎的表里对某些记录加上独占锁之前,需要先在表级别加上一个意向独占锁;
总结:
- 意向共享锁和意向独占锁是表级锁,不会和行级的共享锁和独占锁发生冲突,而且意向锁之间也不会发生冲突,只会和共享表锁和独占锁发生冲突;
- 有了意向锁,由于在对记录加独占锁前,先会加上表级别的意向独占锁,那么在加独占锁时,直接查该表是否有意向独占锁,如果有就意味着表里已经有记录被加了独占锁,这样就不用去遍历表里的记录。
元数据锁、MDL锁(metadata lock)
不需要显式的使用,在访问一个表的时候会自动加上。
作用:会保证读写的安全。
- 当一个表做增删改查操作的时候,会加上MDL读锁。读锁之间不互斥,多个线程可以同时对一张表进行增删改查。
- 当一个表做结构变更的时候,会加上MDL写锁。读写互斥,写写互斥,需要一个等待另一个完成后才执行。
补充:
- 事务中的MDL锁,在语句执行开始时申请,但是语句结束后不会马上释放,会等整个事务提交后再释放。
- 也就是说,不应该出现DDL与DML同时在一个事务里,这样会导致DDL之后的语句阻塞,数据库的线程很快会被爆满。因为DDL会加上MDL写锁,执行之后不会释放。而DDL之后操作会尝试获取DML读锁,读写互斥。所以会一直等待。
如果非要在表上增加字段,做DDL操作如何处理?
可以在语句设置等待时间,如果在这个指定的等待时间里能拿到MDL写锁最好,拿不到也不要阻塞后面的业务语句,先放弃。之后开发人员在通过重试命令重复这个过程。行锁
行锁是两阶段锁,所以介绍一下两阶段锁。
两阶段锁协议:
InnoDB事务中,行锁是在需要的时候加上的,但是并不是不需要了就立即释放,而是等待事务结束后才释放。
所以,如果事务中需要锁多行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。这样可以减少事务之间锁的等待,提高了并发度。
个人总结:相当于读写锁(ReadWriteLock)、主要包括记录锁(对索引下面的数据上锁)、间隙锁(对可以插入的间隙上锁、防止幻读)
死锁
个人总结:就是两个事务想要获取彼此的锁。
避免死锁:使用中间件,对于相同的行的更新,在进入引擎之前排队。防止有大量的死锁检查工作占用资源。