06-07-锁
锁的种类
mysql锁大致可以分成全局锁、表级锁和行锁三类
- 全局锁, 又称为数据库锁,是对整个数据库实例加锁,对整个数据库实例的DDL和DML操作都会被阻塞,直到锁释放。
- 表级锁
- 表锁, Table Lock,是对表加锁,对表的DDL和DML操作都会被阻塞,直到锁释放。
- 元数据锁, meta data lock, MDL
- 行锁
- 共享锁, Shared Lock,又称为读锁,是对一行或多行加锁,其他事务只能对该行或多行进行读操作,直到锁释放。
- 排他锁, Exclusive Lock,又称为写锁,是对一行或多行加锁,其他事务不能对该行或多行进行任何操作,直到锁释放。
- record lock,又称为next-key lock,是对索引记录加锁,在RR隔离级别下,对索引记录加的锁,其他事务只能在当前索引记录和相邻的记录之间进行加锁,直到锁释放。
- gap lock,又称为间隙锁,是对索引记录之间的间隙加锁,在RR隔离级别下,对索引记录之间的间隙加的锁,其他事务只能在当前索引记录和相邻的记录之间进行加锁,直到锁释放。
- next-key lock,又称为gap lock,是对索引记录之间的间隙加锁,在RR隔离级别下,对索引记录之间的间隙加的锁,其他事务只能在当前索引记录和相邻的记录之间进行加锁,直到锁释放。
全局锁
Flush tables with read lock;
官方自带的逻辑备份工具是 mysqldump,当 mysqldump 使用参数–single-transaction 的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。
但当引擎不支持事务时,只能使用FTWRL 命令了。不推荐不使用 set global readonly=true,readonly会被其他逻辑使用(比如判断主从),readonly发生异常会保持该状态。
表级锁
表锁的语法是 lock tables … read/write。
MDL不需要显式使用,在访问一个表的时候会被自动加上。
当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。
当一个长事务还没提交,进行表结构变更操作,会导致后面的事务block。当客户端有重试机制时,新起session请求,会导致库的线程很快就会爆满。
如何安全地给小表加字段?
避免长事务。
在 alter table 语句里面设定等待时间。
MariaDB 已经合并了 AliSQL 的这个功能,所以这两个开源分支目前都支持 DDL NOWAIT/WAIT n 这个语法。
07 | 行锁功过:怎么减少行锁对性能的影响
行锁
Mysql行锁由引擎层实现
两阶段锁
行锁需要事务结束时才释放,这就是两阶段锁。
所以需要合理安排事务中sql执行顺序,尽量把容易冲突的更新语句放在后面。
死锁和死锁检测
设置超时时间,innodb_lock_wait_timeout。
死锁检测,发现死锁主动回滚某个事务,innodb_deadlock_detect 默认on。
假设1000个同时更新一行,则死锁检测操作就是 100 万这个量级的。即使没有死锁,检测也会消耗大量的 CPU 资源。
解决方案:
业务不会出现死锁,可以临时关闭。
在客户端控制并发。
修改MySQL 源码,并发进入引擎之前排队。
将一行数据改为多行,如将一个余额账户分为多个,但在数据减少操作时需考虑小于0的情况。