来源
MySQL锁
什么是锁?
当多个用户访问数据库的共享资源,数据库需要合理地控制资源的【访问规则】。而锁就是用来实现这些访问规则的重要【数据结构】。
锁的分类
全局锁
对整个库进行加锁,只允许读。
使用场景: 对全库做【逻辑备份】
实际操作
- 【
不推荐】使用命令Flush tables with read lock,让数据库处于只读状态,其他线程下的DML,DDL会被阻塞。() - 【
不推荐】使用命令set global readonly=true,但不推荐。因为一是参数readonly通常作为主备库的区别,二是后者的异常处理方式没有第一种好 - 【推荐】通过官方工具mysqldump,使用参数
-single-transaction来一起动一个一致性视图,因为MVCC存在,在备份过程中支持DML操作,不支持DDL操作(可能出现问题)
表级锁
表锁
【不推荐使用,除非没有行锁】。主动使用命令(显示)对表进行加锁或者解锁操作
MDL锁(Meta Data Lock,即元数据锁)
不需要显示使用,访问表时会自动加上,保证读写正确(防止一个线程读时,其他线程修改表结构)。在5.5版本加上,
- 对表做增删改查(DML、DQL)操作时,加【MDL读锁】
- 对表结构做变更(DDL)时,加【MDL写锁】
- 读锁之间不互斥,读写锁之间、写锁之间互斥
锁的申请与释放:在语句执行开始时申请,语句结束之后不会立即释放,而是事务提交之后才释放。即事务不提交,就不释放锁
死锁出现:前面线程A持有读锁(长事务,不释放),线程B申请写锁,则后续申请读锁也都会被阻塞。如何解决?线程B申请不到就取消(设置超时,有的SQL已经执行超时机制)
行锁
由引擎层实现
锁的申请与释放:在需要时申请,在事务提交之后释放。因此根据申请/释放规则,如果事务中需要锁多行,尽量把可能引起竞争的锁放在后面(SQL语句放在靠近commit)
死锁:多个事务之间循环等待
死锁解决策略
- 超时机制:通过设置参数
innodb_lock_wait_timeout,默认50s。不能设置太小,万一不是死锁而是正常锁等待呢? - 发起死锁检测:将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑。即事务执行前检测自己的加入是否会产生死锁