提升工作效率利器:
Mac App Store 上的“Whale - 任务管理、时间、卡片、高效率”
简介:锁是计算机协调多个进程或线程并发访问某一资源变得有序的机制。
一、锁分类
1. 行级锁/表级锁/页面锁
A. 行级锁:是指给索引上的索引项加锁,偏向InnoDB存储引擎;
B. 表级锁:是指给全表加锁,这个是由于没有使用索引导致的,偏向MyISAM存储引擎;
C. 页面锁:开销和加锁时间界于表锁和行锁之间;
2. 共享锁/排它锁
A. 共享锁(S锁):也称读锁,指可以同时读数据,即允许持锁事务读取一行,事务A持有S锁,事务B请求S锁时,会立即被赋予,若请求X锁,需等待释放S锁才可以拿;
B. 排它锁(X锁):也称写锁,指只允许一个事务拿到锁,即允许持锁事务更新或删除一行,事务A持有X锁,事务B请求S、X锁时,需等待释放X锁才可以拿;
3. 意向共享锁/意向排它锁
A. 意向锁(Intention Locks):表明一个事务稍后要获取表中某一行的共享锁或排它锁;
B. 意向共享锁(IS):事务打算给数据行加共享锁时,那么事务在给一个数据行加S锁前必须先取得该表的IS锁;
C. 意向排它锁(IX):事务打算给数据行加排它锁时,那么事务在给一个数据行加X锁前必须先取得该表的IX锁;
D. 意向锁是由存储引擎自己维护的,用户无法手动操作意向锁,在为数据行加共享锁或排它锁之前,InnoDB会先获取该数据行所在的数据表对应的意向锁;
4. 自增锁:指事务插入自增列(ID)的时候需要的锁,一个事务正在插入记录,其他事务插入记录需要等待释放自增锁;
5. 悲观锁/乐观锁。
二、行级锁/表级锁
1. 行级锁
A. 特点
MySQL的行级锁是通过索引加载的,如果sql没有走索引,则会全表扫描,那么对应加表级锁;
行锁开销大,加锁慢,会出现死锁,但发生锁冲突几率低,并发高;
B. 分类:共享锁和排它锁;
C. 行锁升级为表锁:如果没有使用索引条件检索数据,那么InnoDB将对表中所有数据加锁,实际效果就跟加表锁一样;
2. 表级锁
A. 特点
MYISAM引擎只支持表锁,当sql执行时自动加上,InnoDB也支持表锁,是在没有使用索引的时候,就会自动加表锁;
表锁开销小,加锁快,不会出现死锁,但发生锁冲突几率高,并发低;
B. 分类:意向锁和自增锁。
三、共享锁/排它锁
1. 共享锁(Shared Locks)
A. 特点:允许读读可以并行,但是不能做到写读、读写和写写并行;
B. 加锁方式:lock in share mode,如:select * from user where id = 1 lock in share mode;
2. 排它锁(Exclusive Locks)
A. 加锁方式:for update,如:select * from user where id = 1 for update;
B. 分类:记录锁、间隙锁和临键锁;
C. 对于insert、update、delete语句,InnoDB会自动给数据集加排它锁,而对于普通select语句,InnoDB不会加任何锁。
四、记录锁/间隙锁/临键锁
1. 记录锁(Record Locks)
A. 仅仅锁住索引记录的一行,也叫行锁;
b. 锁住的永远是索引记录而非记录本身。
2. 间隙锁(Gap Locks)
A. 定义:是没有匹配记录,锁住索引记录中的间隙,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围,是锁住一个索引区间(左开右闭);
间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据,这是为了防止出现幻读现象。
B. 特点:间隙锁只在事务隔离级别RR下才有,一方面是防止产生幻读的问题,另一方面是为了满足恢复和复制的需要;
C. 产生条件:使用普通索引锁定、使用多列唯一索引、使用唯一索引锁定多行记录;
唯一索引只有锁住多条记录或者一条不存在的记录的时候,才会产生间隙锁,指定给某条存在的记录加锁的时候,只会加记录锁,不会产生间隙锁;
普通索引不管是锁住单条,还是多条记录,都会产生间隙锁。
D. 查看锁:show variables like 'innodb_locks_unsafe_for_binlog',默认值为OFF,即启用间隙锁。
3. 临键锁(Next-key Locks)
A. 定义:是匹配到了记录,指锁住索引记录和索引间隙,是innodb引擎默认的加锁方式;
B. 是记录锁和间隙锁的组合;
C. 使用在不同的场景会演变成不同的锁类型(记录锁还是间隙锁)。
五、插入意向锁(Insert Intention Locks)
1. 是一种间隙锁,而非意向锁,在insert操作时产生,属于行锁;
2. 他不会阻止任何锁,对于插入的记录会持有一个记录锁。
六、锁相关
1. 查看当前运行的所有事务:select * from information_schema.innodb_trx;
A. 删除相应进程:kill trx_mysql_thread_id;
2. 查看正在锁的事务:select * from information_schema.innodb_locks;
3. 查看等待锁的事务:select * from information_schema.innodb_lock_waits;
八、死锁
可参考:【mysql】死锁-产生原因和解决方法