共享读锁(S):手动添加,允许一个事务去读一行,其他事务可以读数据,但不能修改数据。
SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE -- 共享读锁 手动添加排他写锁(X):自动添加,指的是一个事务在一行数据加上排他锁后,其他事务不能再在其上加其他的锁。
InnoDB也实现了表级锁,也就是意向锁,意向锁是mysql内部使用的,不需要用户干预。
两阶段锁(2PL)两阶段锁讲的是锁操作分为两个阶段:加锁阶段和解锁阶段。
加锁阶段:只加锁,不放锁。
解锁阶段:只放锁,不加锁。
行锁演示InnoDB行锁是通过给索引上的索引项加锁来实现的,因此只有通过索引条件检索的数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁!
行读锁
1、我们利用session1给id=1的行加读锁,使用索引。
session1: begin;select * from mylock where ID=1 lock in share mode;
2、由于行锁锁定的是行,所以利用session2修改别的行例如id=2是可以的,修改id=1就不行了。
session2:update mylock set name='M' where id=2;session2:update mylock set name='M' where id=1;
3、当session1提交后,session2才可以修改。
session1: commit;session2:update mylock set name='M' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
关于行锁,我们要注意使用索引加行锁 ,未锁定的行可以访问。
行读锁升级为表锁
mylock表中id加了索引,name没有加索引,当我们对name加行读锁时,就会出现行读锁升级为表锁。
1、session1开启事务
session1: begin;2、手动加name='c'的行读锁,未使用索引
select * from mylock where name='c' lock in share mode;3、session2修改阻塞,未用索引行锁升级为表锁
update mylock set name='N' where id=2;4、session1提交事务或者 rollback 释放读锁
commit;5、session2就会修改成功
update mylock set name='N' where id=2;行写锁
1、session1开启事务并且手动加id=1的行写锁。
session1: begin;select * from mylock where id=1 for update;
2、这里有一个特别重要的知识点,很多人会弄错!
排他锁锁住一行数据后,其他事务就不能读取和修改该行数据,其实不是这样的!
排他锁指的是一个事务在一行数据加上排他锁后,其他事务不能再在其上加其他的锁。MySQL InnoDB引擎默认的修改数据语句:update,delete,insert都会自动给数据加上排他锁,select语句默认不会加任何锁类型,如果加排他锁可以使用select …for update语句,加共享锁可以使用select … lock in share mode语句。所以其他事务是不能修改加过排他锁的数据行,其他事务也不能通过for update和lock in share mode锁的方式查询数据,但可以直接通过select …from…查询数据,因为普通查询没有任何锁机制。
所以session2可以访问id=1的数据行。
session2: select * from mylock where id=1 ;3、但是不能给它继续加锁
session2: select * from mylock where id=1 lock in share mode ;4、session1提交事务或者rollback释放写锁,session2才会执行成功
间隙锁根据检索条件向左寻找最靠近检索条件的记录值A,作为左区间,向右寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B)。根据图中where number=5的话,那么间隙锁的区间范围为(4,11);
间隙锁防止两种情况
防止插入间隙内的数据
防止已有数据更新为间隙内的数据
间隙情况:
id、number均在间隙内
id、number均在间隙外
id在间隙内、number在间隙外
id在间隙外,number在间隙内