innodb的锁,我们可以从几个维度来分析,分为级别,类型
级别
行级锁
表级锁
类型
共享锁(S),也称为写锁, 级别:行级锁
意向共享锁(IS),也称为意向写锁 级别:表级锁
排他锁(X),也称为读锁 属于行级锁 级别: 行级锁
意向排他锁(IX),也称为意向读锁 级别: 表级锁
行锁的算法
Record Locks
Gap Locks
Next-Key Locks
Insert intention Locks
AUTO-INC Locks
Predicate Locks for Spatial Indexes
锁的兼容性请看下图
我们就先从类型讲起
共享锁
允许持有锁的事务读取行
假如有一个a事务获取了x行的共享锁,这时候b事务也来请求x行的锁,那么会进行一下处理
如果b请求的是x行的共享锁,那么会立刻授予,这时候a事务和b事务都拥有x行的共享锁
如果b请求的是x的排他锁,那么不会立刻授予,因为共享锁和排他锁是不兼容的
排他锁
允许持有锁的事务更新或删除行。
假如有一个a事务获取了x行的排他锁,这时候b事务也来请求x行的锁,这时候不管b事务请求的锁是共享锁还是排他锁,都不能立即授予,只能等到a事务释放了在x行的排他锁才能授予b事务,因为排他锁与任何的锁都不兼容
意向锁的讲述
innodb支持多粒度锁定,这种锁定允许事务在行级上的锁和表级上的锁同行存在,为了支持在不同粒度上进行操作,innodb存储引擎支持一个额外的锁方式,称之为意向锁,意向锁是将锁定的对象分为多个层次,意向锁意味着事务希望在更细粒度上进行加锁,也就是如果一个事务需要针对记录R来加排他锁,那么就需要对记录R所在的数据库,表,页进行加锁,最后对记录R加排他锁,如果有任何一个部分导致等待,那么该操作需要粗粒度锁的完成。
意向锁是表级锁,设计目的主要是为了在下一个事务中揭示下一行将被请求的锁类型,由于innodb存储引擎支持的是行级别的锁,因此意向锁其实不会阻塞除全表扫描以外的任何请求。
上面的可能不好理解,下面我说一个实际的例子
我们有一个student表
mysql> show create table student;
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| student | CREATE TABLE student (
id int(11) NOT NULL AUTO_INCREMENT,
student_num int(11) NOT NULL DEFAULT '0' COMMENT '学号',
name varchar(32) NOT NULL DEFAULT '' COMMENT '学生姓名',
PRIMARY KEY (id),
UNIQUE KEY uqidx_student_num (student_num)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 |
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select * from student;
+----+-------------+----------+
| id | student_num | name |
+----+-------------+----------+
| 1 | 1 | zhangsan |
| 2 | 2 | lisi |
| 3 | 3 | wangwu |
| 4 | 4 | zhaoliu |
| 5 | 5 | liqi |
+----+-------------+----------+
5 rows in set (0.00 sec)
session1
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from student where student_num=4 for update;
+----+-------------+---------+
| id | student_num | name |
+----+-------------+---------+
| 4 | 4 | zhaoliu |
+----+-------------+---------+
1 row in set (0.00 sec)
session2
mysql> LOCK TABLE student write;
这时候我们发现session2一直在等待,因为session2想获取student整个表的写锁,如果session2申请成功了, 它是可以修改student表的任意一行的,那么大家会说session1已经获取了student_num=4的排他锁呢,如果session2申请成功了,那么student_num=4的记录也会被session2修改了,所以说这时候session2肯定是会阻塞的,那么数据库是根据什么方法来判断使得session2被阻塞呢,无非就下面两种方法
判断这个表是否被其他事务用表锁给锁住
判断这个表的每一行是否有