MySQL-锁 个人理解

作者: 大黑跟小白的日常 | 来源:发表于2021-01-16 17:56 被阅读0次

    行锁

    对数据库表行记录进行加锁。
    比如: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锁 兼容、互斥关系


    image.png

    间隙锁(Gap Lock)

    条件:RR事务隔离级别下
    锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。
    间隙锁是封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。

    下图就是六条记录,并且形成了7个间隙。 那么对间隙上锁,就是间隙锁。


    image.png

    间隙锁可能出现的问题演示
    演示1:

    image.png
    image.png

    如上图,如果事务1 步骤5 插入的是 id= 98 ,事务2 步骤6 插入的是 id=99 数据,那么 不会出现 阻塞 死锁问题。

    演示2:


    image.png

    表锁

    对整个表进行上锁的操作,叫表锁
    对表进行加锁
    LOCK TABLES table_name WRITE/READ;
    解锁 (释放当前会话所加的表锁)
    UNLOCK TABLES;

    如上方式对表进行加锁,是一种绝对加锁的方式。

    如果 对表 加了写锁 以后,其它 会话,无法读表中任何数据(普通select也不行),无法做任何修改,只能阻塞,直到 表锁 释放;

    如果 对表 加了读锁 以后,其它会话可以 继续读取数据,或者继续对表加读锁(共享锁),但是在加了读锁之后,其它会话就不能去修改表中任何数据,直到锁释放;

    如下 操作,也会 对 表整个范围进行加锁(不同种类锁,范围覆盖整个表,也叫表锁)。

    在RR的隔离级别下,当color字段 为 非索引字段时:
    update table_name set field1=param1 where color='red';
    全表扫描,最终导致 上锁的范围为整个表,其中有 X锁 有 Gap锁。


    image.png

    从锁定范围来讲,这里也叫表锁;

    插入意向锁(InnoDB)

    多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此。

    在插入数据时,会产生插入意向锁,会对意向id位置进行上锁(非Gap锁),属于排他锁;

    事务1 插入id为1的数据,挂起事务不提交,事务2 也插入id为1的数据,则需要阻塞,直到事务1释放 意向锁。事务2 两种结果:1、主键冲突,2、执行成功;

    如果事务1 插入id为1数据,事务2插入id为2数据,则互不影响。

    如上内容,如有 疑问,欢迎沟通指正。

    相关文章

      网友评论

        本文标题:MySQL-锁 个人理解

        本文链接:https://www.haomeiwen.com/subject/mumevktx.html