行锁
对数据库表行记录进行加锁。
比如:id为 table1 表主键
当 id=1 数据 存在 的情况下,SQL语句:
update table1 set field1=param1 where id=1;
(
或 delete from table1 where id=1;
或 select * from table1 where id=1 for update;
)
实则是当前事务(事务T)对 id=1的这行数据 加的 行锁,直到事务提交或回滚,锁释放。
写锁、排他锁(X锁)
如上例子,实则也是对id=1的这行数据加的是一个写锁,它是一个排他锁。
排他锁(X锁):
若 事务T 对 数据a 加上X锁 ,事务T 就具备了 数据a 的读写权限,其它事务不能再对 数据a 加任何锁,直到 事务T 释放 数据a 上的锁。
行锁 一定是 排他锁吗?
不一定!
行锁字面意思 就是 对 行进行加锁,只要对行进行加锁都可以叫行锁。但是从另一个层面讲,对这 行数据 进行加锁不是非得加 排他锁,也可以对行数据加 共享锁;如下
SELECT * FROM table1 WHERE id=1 LOCK IN SHARE MODE;
在 id =1 数据存在的情况下 ,这里实则是对 id=1的数据行加的 共享锁LOCK IN SHARE MODE;
读锁、共享锁(S锁)
如:
SELECT * FROM table1 WHERE id=1 LOCK IN SHARE MODE;
若事务T对数据对象A加上S锁,在事务T未释放数据A的S锁之前,其它事务也可以对数据对象A加S锁,针对数据A上的这把锁是共享的,所以叫 共享锁。
但是 在两个事务都持有了数据A的S锁之后,事务1未结束前是不允许事务2 针对 锁定的数据 做 具体写操作的,同样,事务2在未结束前也不允许事务1 对锁定的数据做 写操作。
如果 事务1 事务2 持有了同一把 共享锁,如果这时 事务1 对锁定的数据 做写操作,那么会被阻塞。如果事务2 在事务1被阻塞的情况下 也执行写操作,那么会出现死锁问题。
其它情况下的共享锁:
当主键id=1的数据不存在时,MySQL RR(默认事务隔离级别——可重复读) 隔离级别下,如下:
select * from table1 where id = 1 for update;
或
update table1 set filed1=param1 where id = 1;
或
INSERT INTO table1
SELECT 1,'Tom','male','19' FROM DUAL
WHERE NOT EXISTS (SELECT *FROM table1 where id = 1);
如上三条SQL语句,实则也是 对 id=1 所处的 主键间隙空间 加的 共享锁,这里 也是 一个 间隙锁。(RC不存在间隙锁)
图解 S锁与X锁 兼容、互斥关系
间隙锁(Gap Lock)
条件:RR事务隔离级别下
锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。
间隙锁是封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。
下图就是六条记录,并且形成了7个间隙。 那么对间隙上锁,就是间隙锁。
间隙锁可能出现的问题演示
演示1:
如上图,如果事务1 步骤5 插入的是 id= 98 ,事务2 步骤6 插入的是 id=99 数据,那么 不会出现 阻塞 死锁问题。
演示2:
表锁
对整个表进行上锁的操作,叫表锁
对表进行加锁
LOCK TABLES table_name WRITE/READ;
解锁 (释放当前会话所加的表锁)
UNLOCK TABLES;
如上方式对表进行加锁,是一种绝对加锁的方式。
如果 对表 加了写锁 以后,其它 会话,无法读表中任何数据(普通select也不行),无法做任何修改,只能阻塞,直到 表锁 释放;
如果 对表 加了读锁 以后,其它会话可以 继续读取数据,或者继续对表加读锁(共享锁),但是在加了读锁之后,其它会话就不能去修改表中任何数据,直到锁释放;
如下 操作,也会 对 表整个范围进行加锁(不同种类锁,范围覆盖整个表,也叫表锁)。
在RR的隔离级别下,当color字段 为 非索引字段时:
update table_name set field1=param1 where color='red';
全表扫描,最终导致 上锁的范围为整个表,其中有 X锁 有 Gap锁。
从锁定范围来讲,这里也叫表锁;
插入意向锁(InnoDB)
多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此。
在插入数据时,会产生插入意向锁,会对意向id位置进行上锁(非Gap锁),属于排他锁;
事务1 插入id为1的数据,挂起事务不提交,事务2 也插入id为1的数据,则需要阻塞,直到事务1释放 意向锁。事务2 两种结果:1、主键冲突,2、执行成功;
如果事务1 插入id为1数据,事务2插入id为2数据,则互不影响。
如上内容,如有 疑问,欢迎沟通指正。