mysql-innodb锁类型详细介绍
mysql支持三种级别的锁定机制:表级锁定(table-level),行级锁定(row-level),页级锁定(page-level)。
1.表级锁定(table-level)
表级锁是mysql中锁粒度最大的锁定机制,一次会将整张表锁定,不会出现死锁问题
2.行级锁定(row-level)
行级锁是锁粒度最小的锁定机制。由于锁粒度最小,所以锁定资源发生的争用也就最小,这样提高了应用程序并发处理的能力同时提高了整个系统的性能,但是每次获取锁和释放锁都要做很多事情,带来的消耗也就增加,也最容易发生死锁。
3.页级锁定(page-level)
页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样
是介于上面二者之间。另外,页级锁定和行级锁定一样,会发生死锁。
mysql这三种锁的特性可以大致归纳如下: 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
innodb存储引擎与myisam最大的不同就是:innodb支持事务;采用行级锁
可以通过检查Innodb_row_lock变量来分析系统上行锁的争夺情况:
innodb同时为了支持表锁和行锁的共存,实现多粒度的锁定机制,还有两种意向锁(intention locks):
如果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。
意向锁是InnoDB自动加的,不需用户干预。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁;事务可以通过以下语句显示给记录集加共享锁或排他锁。
排他锁(X):SELECT ... FOR UPDATE
单条索引记录上加锁,record lock锁住的永远是索引,而非记录本身,即使该表上没有任何索引,那么innodb会在后台创建一个
隐藏的聚集主键索引,那么锁住的就是这个隐藏的聚集主键索引。所以说当一条sql没有走任何索引时,那么将会在每一条聚集索引后面加X锁,这个类似于表锁
在索引记录之间的间隙中加锁,或者是在某一条索引记录之前或者之后加锁,并不包括该索引记录本身。
Next-Key Locks
例如:某普通索引列当前值有:1, 10, 20,那么此时它的防插入锁区间分别是:
(-∞, 1], (1, 10], (10, 20], (20, +∞)
注意:innodb通过范围条件加锁时使用next-key锁外,如果使用相等条件请求给一个不存在的记录加锁,innodb会使用next-key锁。
下列SQL语句自带的行锁级别为:
insert——记录锁、update——防插入锁、delete——防插入锁
此外,若查询的列包含唯一索引或主键,则行锁将被自动降级到记录锁
(1)在不通过索引条件查询时,innodb会锁定表中的所有记录
(2)mysql的行锁是针对索引加的锁,所以虽然是访问不同行的记录,如果使用相同的索引键,是会出现锁冲突的
(3)当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,不论是使用主键索引,唯一索引或普通索引,innodb都会使用行锁来对数据加锁
(4)即使在条件中使用了索引字段,但是否使用索引来检索数据是由mysql通过判断不同计划的代价来决定的,如果mysql认为全表扫描效率更高,它就不会使用索引,这种情况下innodb会对所有记录加锁。
译者介绍:家华,从事mysqlDBA的工作,记录自己对mysql的一些总结