共享锁(S Lock)
共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到最新数据。
1、多个事务的查询语句可以共用一把共享锁;
2、如果只有一个事务拿到了共享锁,则该事务可以对数据进行 UPDATE DETELE 等操作;
3、如果有多个事务拿到了共享锁,则所有事务都不能对数据进行 UPDATE DETELE 等操作。
加锁方式:select…lock in share mode
排它锁(X Lock)
排他锁又称为写锁,简称X锁,顾名思义,排它锁不能与其它锁并存,而且只有一个事务能拿到某一数据行的排它锁,其余事务不能再获取该数据行的所有锁。
1、只有一个事务能获取该数据的排它锁;
2、一旦有一个事务获取了该数据的排它锁之后,其余事务对于该数据的操作将会被阻塞,直至锁释放。
加锁方式:select…for update
1、意向锁 (Intention Locks)
意向锁是一种表级别的锁,意味着事务在更细的粒度上进行加锁。
意向共享锁(IS Lock):事务想要获得一张表中某几行的共享锁;
意向排他锁(IX Lock):事务想要获得一张表中某几行的排他锁;
举个例子,事务1在表1上加了S锁后,事务2想要更改某行记录,需要添加IX锁,由于不兼容,所以需要等待S锁释放;如果事务1在表1上加了IS锁,事务2添加的IX锁与IS锁兼容,就可以操作,这就实现了更细粒度的加锁。
意向锁相互兼容,因为IX、IS只是表明申请更低层次级别元素(比如 page、记录)的X、S操作。
因为上了表级S锁后,不允许其他事务再加X锁,所以表级S锁和X、IX锁不兼容
上了表级X锁后,会修改数据,所以表级X锁和 IS、IX、S、X(即使是行排他锁,因为表级锁定的行肯定包括行级速订的行,所以表级X和IX、行级X)不兼容。
注意:上了行级X锁后,行级X锁不会因为有别的事务上了IX而堵塞,一个mysql是允许多个行级X锁同时存在的,只要他们不是针对相同的数据行。
**2、记录锁(Record Locks) **
(1)记录锁是一种行级锁, 仅仅锁住索引记录的一行,在单条索引记录上加锁。
(2)record lock锁住的永远是索引,而非记录本身,即使该表上没有任何索引,那么innodb会在后台创建一个隐藏的聚集主键索引,那么锁住的就是这个隐藏的聚集主键索引。
所以说当一条sql没有走任何索引时,那么将会在每一条聚合索引后面加X锁,这个类似于表锁,但原理上和表锁应该是完全不同的。
3、间隙锁(Gap Locks)
(1)区间锁是一种行级锁, 仅仅锁住一个索引区间(开区间,不包括双端端点)。
(2)在索引记录之间的间隙中加锁,或者是在某一条索引记录之前或者之后加锁,并不包括该索引记录本身。
比如在 1、2、3中,间隙锁的可能值有 (∞, 1),(1, 2),(2, ∞),
(3)间隙锁可用于防止幻读,保证索引间的不会被插入数据
4、临键锁(Next-Key Lock)
临建锁是记录锁与间隙锁的组合,即:既包含索引记录,又包含索引区间,主要是为了解决幻读。
(1)record lock + gap lock, 左开右闭区间。
(2)默认情况下,innodb使用next-key locks来锁定记录。select … for update
(3)但当查询的索引含有唯一属性的时候,Next-Key Lock 会进行优化,将其降级为Record Lock,即仅锁住索引本身,不是范围。
(4)Next-Key Lock在不同的场景中会退化:
5、插入意向锁(Insert Intention Lock)
插入意向锁是间隙锁的一种,专门针对insert操作的。即多个事务在同一个索引、同一个范围区间内插入记录时,如果插入的位置不冲突,则不会阻塞彼此;
举个例子:在可重复读隔离级别下,对PK ID为10-20的数据进行操作:
事务1在10-20的记录中插入了一行:
insert into table value(11, xx)
事务2在10-20的记录中插入了一行:
insert into table value(12, xx)
由于两条插入的记录不冲突,所以会使用插入意向锁,且事务2不会被阻塞。
6、自增锁(AUTO-INC Locks)
UTO-INC锁是一种特殊的表级锁,发生涉及AUTO_INCREMENT列的事务性插入操作时产生。
自增锁是一种特殊的表级别锁,专门针对事务插入AUTO-INCREMENT类型的列。
即一个事务正在往表中插入记录时,其他事务的插入必须等待,以便第1个事务插入的行得到的主键值是连续的。
举个例子:在可重复读隔离级别下,PK ID为自增主键
表中已有主键ID为1、2、3的3条记录。
事务1插入了一行:
insert into table value(‘aa’)
得到一条(4,’aa’)的记录,未提交;
此时
事务2中插入了一行:
insert into table value(‘bb’)
这时会被阻塞,即用到了插入意向锁的概念。