Contents
1.8. 08.锁¶
为保证数据一致性,让各种共享资源在被并发访问时变得有序而设置的规则
不同的存储引擎支持不同的锁机制。
InnoDB支持行锁,有时也会升级为表锁;
MyISAM只支持表锁 表锁的特点是开销小、加锁快;不会出现死锁;锁粒度大,发生锁冲突概率高,并发度相对低
行锁特点是开销大,加锁慢;会出现死锁;锁粒度小,发生锁冲突概率低,并发度相对行锁较高
1.8.1. InnoDB的锁类型¶
InnoDB的行锁主要有读锁(共享锁)、写锁(排他锁)、意向锁和MDL锁
读锁¶
简称S锁,一个事务获取了一个数据行的读锁,其他事务也可以获得该行的读锁,但不能获得写锁
一个事务在读取一个数据行时,其他事务也可以读,但不能对该数据进行增删改操作
1、一致性非锁定读,自动提交模式下的select查询语句,不需加任何锁,直接返回结果
2、通过select ... lock in share mode,在被读取的行记录或记录范围上加读锁,其他事务写会被阻塞
写锁¶
简称X锁,写锁优化级最高,一个事务获得后,其他事务不能再获得其他锁
一些DML语句的操作都会对行记录加写锁
特殊的select for update会对读取的行加写锁
DML锁¶
meta data lock,简称DML锁,用于保证表中元数据的信息。一个会话开启查询事务后,会自动获得一个MDL锁,其他会话就不能执行任何DDL语句
意向锁¶
InnoDB中,意向锁是表级锁,包括:意向共享锁和意向排他锁
作用类似DML锁,防止在事务进行过程中,执行DDL语句的操作而导致数据不一致
意向共享锁IS,给一个数据行加共享锁前必须先取得该表的IS锁
意向排他锁IX,给一个数据行加排他锁前必须先取得该表的IX锁
1.8.2. InnoDB行锁种类¶
InnoDB在默认事务隔离级别RR(可重复读repetable read),且参数innodb_locks_unsafe_for_binlog=0模式下,行锁有三种:
1)记录锁,单个行记录的锁 record lock
#主键和唯一索引都是行记录的锁模式,在PC隔离级别下,只有record lock记录锁模式
2)间隙锁 GAP Lock
3)记录锁和间隙锁的组合叫作next-key lock
#普通索引默认就是next-key lock模式
记录锁,单个行记录的锁¶
更新同一行数据时,会出现锁等待的现象,InnoDB的行锁是加在索引项上面的
show index from tt;
间隙锁Gap lock¶
在RR事务隔离级别,为避免幻读现象引入Gap lock,它只锁定行记录数据的范围,不包含记录本身,即不允许在此范围内插入任何数据
加锁方法:select * from tt where score<80 lock share mode;插入score小于80的记录将出现锁等待
间隙锁只针对RR隔离级别才管用,它就是用来避免幻读现象发生的
RC隔离级别下是允许出现幻读现象的
Next-key Locks¶
Next-key Lock是记录锁Record Lock与间隙锁Gap lock的组合,当InnoDB扫描索引记录时,先对选中的索引记录加入记录锁,再对索引记录两加的间隙加上间隙锁
select * from tt where score<85 for update;再另一个会话中插入score=85的记录,无法插入成功,说明不光锁定了<85的范围,也锁了85这个记录本身
1.8.3. 锁等待和死锁¶
锁等待,一个事务过程中产生的锁,其他事务需要等待上一个事务释放它的锁,才能占用该资源。会一直等待,直到锁等待超时
innodb_lock_wait_timeout = 10 单位秒
死锁,两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象。报错为Deadlock found when tring to get lock;try restarting transaction
避免死锁的四个方法:
1)若不同程序会并发存取多个表,或涉及多行记录时,尽量约定以相同的顺序访问表,可以大大降低死锁的机会
2)业务中尽量采用小事务,避免使用大事务,要及时提交或回滚事务,可减少死锁产生概率
3)在同一事务中,尽可能做到一次锁定所需资源,减少死锁产生概率
4)对于非常容易产生死锁的业务部分,可尝试升级锁粒度,通过表锁定来减少死锁产生概率
1.8.4. 锁问题的监控¶
通常情况下,当出现锁问题时,我们习惯性通过show full processlist和show engine innodb status命令来判断
事务中锁问题的情况。
show full processlist
show engine innodb staus
三张表
information_schema.INNODB_TRX、INNODB_LOCKS、INNODB_LOCK_WAITS