MySQL 的锁机制比较简单, 最显著的特点是不同的存储引擎支持不同的锁机制. InnoDB 支持行锁, 有时也会升级为表锁; myisam 只支持表锁.
表锁的特点就是开销小, 加锁快; 不会出现死锁; 锁粒度大, 发生锁冲突的概率高, 并发度相对低.
行锁的特点就是开销大, 加锁慢; 会出现死锁; 锁粒度小, 发生锁冲突的概率低, 并发度也相对较高.
1,InnoDB 的锁类型:
主要有: 读锁(共享锁), 写锁(排他锁), 意向锁和 MDL 锁.
1: 读锁:
读锁, 简称 S 锁, 一个事务获取了一个数据行的读锁, 其他事务能获得改行对应的读锁, 但不能获得写锁, 即一个事务在读取一个数据行时, 其他事务也可以读, 但不能对该数据行进行行增删改的操作.
读锁有两种 select 方式的应用, 第一种是自动提交模式下的 select 查询语句, 不需要加任何锁, 直接返回查询结果, 这就是一致性非锁定读. 第二种就是通过 select...lock in share mode 在被读取的行记录或行记录范围上加一个读锁, 让其他事务可以读, 但是要想申请加写锁, 那就会被阻塞.
2: 写锁:
写锁, 简称 X 锁, 一个事务获取了一个数据行的写锁, 其他事务就不能再获取改行的其他锁, 写锁优先级最高.
写锁的应用就很简单了, 一些 DML 语句的操作都会对行记录加写锁.
比较特殊的是 select for update, 它会对读取的行记录加上一个写锁, 那么其他任何事务就不能对锁定的行加上任何锁了, 要不然会被阻塞.
3:MDL 锁
MySQL5.5 引入了 meta data lock, 简称 MDL 锁, 用于保证表中元数据的信息. 在会话 A 中, 表开启了查询事务后, 会自动获得一个 MDL 锁, 会话 B 就不可以执行任何 DDL 语句的操作.
不能执行为表中添加字段的操作, 会用 DML 锁来保证数据之间的一致性.
4: 意向锁
在 MySQL InnoDB 存储引擎中, 意向锁就是表级锁. 而且有两种意向锁的类型, 分别是意向共享锁 和 意向排他锁.
意向共享锁 (IS) 是指在给一个数据行加共享锁前必须先取得该表的 IS 锁.
意向排他锁 (IX) 是指在给一个数据行加排他锁前必须先取得该表的 IX 锁.
其实意向锁的作用跟 MDL 类似, 都是防止在事务进行过程中, 执行 DDL 语句的操作而导致数据的不一致.
2,InnoDB 行锁种类:
InnoDB 的行锁是通过给索引项加锁实现的(也就是说: 通过以位图方式对 index page 加锁机制来实现的.), 这就意味着只有通过索引条件检索数据时, InnoDB 才使用行锁, 否则使用表锁. 也就是说, 如果批量 update, 如果条件的字段没有索引, 将会锁表!!!!! 如果有索引 只会出现行锁!
InnoDB 在默认的事务隔离级别为 RR, 并且参数 InnoDB_locks_unsafe_for_binlog=0 的模式下, 行锁的种类有三种.
1: 单个行记录的锁(record lock); 注: 主键和唯一索引都是行记录的锁模式. 在 RC 隔离级别下, 只有 record lock 记录锁模式;
2: 间隙锁(GAP lock)
3: 记录锁和间隙锁的组合叫作 next-key lock.(当 InnoDB 扫描索引记录时, 会先对选中的索引记录加上记录锁, 在对索引记录两边的间隙上加上间隙锁)
注意:
InnoDB 的行锁其实是加载索引项上面的.
RC 隔离级别下是允许出现幻读现象的.
3, 锁等待和死锁:
锁等待: 是指一个事务过程中产生的锁, 其他事务需要等待上一个事务释放它的锁, 才能占用该资源. 如果该事务一直不释放, 就需要持续等待下去, 直到超过了锁等待时间, 会报一个等待超时的错误. MySQL 中通过 InnoDB_lock_wait_timeout 参数控制, 单位是秒.
show variables like '%InnoDB_lock_wait%'; --- 查看锁等待超时时间
死锁: 是指两个或两个以上的进程在执行过程中, 因争夺资源而造成的一种互相等待的现象, 就是所谓的锁资源请求产生了回路现象, 即死循环. 常见的错误时 deadlock found when trying to get lock;try restarting transaction.
InnoDB 存储引擎可以自动检测死锁, 并自动回滚该事务.
避免死锁的方法:
1: 如果不同程序会并发存取多个表, 或者涉及多行记录时, 尽量约定以相同的顺序访问表, 可以大大降低死锁的机会.
2: 业务中尽量采用小事务, 避免使用大事务, 要及时提交或者回滚事务, 可减少死锁发生的概率.
3: 在同一个事务中, 尽可能做到一次锁定所需要的所有资源, 减少死锁产生的概率.
4: 对于非常容易产生死锁的业务部分, 可以尝试使用升级锁粒度, 通过表锁定来减少死锁产生的概率.
4, 锁监控的方法:
可以使用: show full processlist 或者 show engine InnoDB status 命令来判断事务中锁的问题的情况.
还可以查看 3 张表: information_schema 下的: InnoDB_trx,innodb_locks,InnoDB_lock_waits
来源: http://www.linuxidc.com/Linux/2018-11/155501.htm