InnoDB 实现了以下两种类型的行锁。
-
共享锁(S):又称为读锁,简称S锁,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
-
排他锁(X):又称为写锁,简称X锁,排他锁就是不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务是可以对数据就行读取和修改。
对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);
对于普通SELECT语句,InnoDB不会加任何锁;
可以通过以下语句显示给记录集加共享锁或排他锁 。
共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排他锁(X) :SELECT * FROM table_name WHERE ... FOR UPDATE
案例(源码):
create table test_innodb_lock(
id int(11),
name varchar(16),
sex varchar(1)
)engine = innodb default charset=utf8;
insert into test_innodb_lock values(1,'100','1');
insert into test_innodb_lock values(3,'3','1');
insert into test_innodb_lock values(4,'400','0');
insert into test_innodb_lock values(5,'500','1');
insert into test_innodb_lock values(6,'600','0');
insert into test_innodb_lock values(7,'700','0');
insert into test_innodb_lock values(8,'800','1');
insert into test_innodb_lock values(9,'900','1');
insert into test_innodb_lock values(1,'200','0');
create index idx_test_innodb_lock_id on test_innodb_lock(id);
create index idx_test_innodb_lock_name on test_innodb_lock(name);
首先将自动提交事务关闭并且进行查询操作:
dosA窗口(设置X锁):
dosB窗口:
窗口A进行更新操作:
窗口B进行更新操作:(持续等待A释放资源)
当dosA提交事务,释放资源后:
dosB更新操作立即执行:
行级锁:
dosA窗口:
dosB窗口:
dosA窗口,进行更新操作:
dosB窗口,进行更新操作(等待,因为资源被A占用):
dosA窗口,提交事务:
dosB窗口,立即执行更新操作:
在此过程中,如果dosB窗口,对其他数据操作将不会被阻塞:
间隙锁危害
当我们用范围条件,而不是使用相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据进行加锁; 对于键值在条件范围内但并不存在的记录,叫做 "间隙(GAP)" , InnoDB也会对这个 "间隙" 加锁,这种锁机制就是所谓的 间隙锁(Next-Key锁) 。
dosA窗口,范围查询:
dosB窗口(只有当dosA窗口提交,才能进行插入数据,否则一直阻塞):
在dosB窗口中,对其他列进行插入操作也不能插入,一直阻塞!直到dosA窗口释放资源。