美文网首页一些收藏mysql
mysql共享锁vs排他锁

mysql共享锁vs排他锁

作者: sunpy | 来源:发表于2022-09-04 18:51 被阅读0次

    读操作 - 共享锁(InnoDB悲观锁)


    因为mysql是自动提交,但是我们要实验不让自动提交使用命令set autocommit=0;

    共享锁结论:
    多个会话共享同一把锁。

    共享锁/会话session 读操作 写操作 锁操作
    当前session 可以 可以 可以
    其他session 可以 阻塞等待操作session的commit(超时报错) 可以

    加锁操作:多个会话都可以加锁。
    读操作:多个会话共享同一把锁,每个会话都可以去读数据。
    写操作:但是对于写数据,如果一个会话写数据了,那么其他会话都要阻塞等待。

    • 如果当前session修改了值,但是还没有commit提交,那么其他session无法修改表中的所有记录,只能等待超时。
    • 其他session可以select查询数据,但是查询的结果是旧数据。

    语句:

    select XXXXXXX lock in share mode;
    

    实验:

    session1 session2
    set autocommit =0;
    select * from edu_user lock in share mode;
    select * from edu_user;
    update edu_user set password="456789" where username = "王五";
    update edu_user set password="012345" where username = "王五";
    等待:1205 - Lock wait timeout exceeded; try restarting transaction
    commit;

    结果:

    mysql> select password from edu_user where username="王五";
    +----------+
    | password |
    +----------+
    | 456789   |
    +----------+
    1 row in set (0.29 sec)
    

    说明:

    • 当前session1获得共享锁,session2也可以继续添加共享锁查询记录。
    • 但是session2想要写记录,将会处于阻塞状态。超过了指定时间(50s)将报错。虽然session1写记录,但是必须要提交事务,session2才可见。
    • 所以select * from t lock in share mode;一般配合事务commit命令使用。
    • 查询共享锁等待时间
    mysql> show variables like '%innodb_lock_wait_timeout%';
    +--------------------------+-------+
    | Variable_name            | Value |
    +--------------------------+-------+
    | innodb_lock_wait_timeout | 50    |
    +--------------------------+-------+
    1 row in set (0.00 sec)
    

    读操作 - 排他锁(InnoDB悲观锁 )


    排他锁结论:
    当前事务加了排他锁之后,其他事务什么锁都不能加。

    排他锁/会话session 读操作 写操作 锁操作
    当前session 可以 可以 可以
    其他session 可以 阻塞等待(超时报错) 阻塞等待(超时报错)

    加锁操作:如果多个session的其中一个session加锁了,那么其他session只能阻塞。
    读操作:多个session可以读。
    写操作:如果一个session的其中一个session加锁了,那么其他session写操作阻塞。

    语句:

    select XXXXXXX for update;
    
    # 自动:delete / update / insert 默认加上排他锁
    # 手动:select * from table for update
    

    实验:

    session1 session2
    set autocommit =0;
    select * from edu_user for update; set autocommit =0;
    成功:select * from edu_user;
    阻塞:select * from edu_user for update;
    update edu_user set password="456789" where username = "王五";
    update edu_user set password = "13579" where username="王五";
    等待:1205 - Lock wait timeout exceeded; try restarting transaction
    commit;

    说明:
    当前事务添加了排他锁后,其他事务想要添加锁都将被阻塞。

    写操作 - 排他锁(InnoDB悲观锁 )


    delete / update / insert 默认会自动加上排他锁。

    update操作:
    获取需要更新的一条记录的位置,使用排他锁锁定该记录。

    session1 session2
    set autocommit =0;
    update edu_user set username = "李保国" where id = '5045dfba5f5b4cb5b805c379fc123456'; set autocommit =0;
    阻塞:update edu_user set username = "李大嘴" where id = '5045dfba5f5b4cb5b805c379fc123456';
    commit; 字段改变为李保国
    执行:update edu_user set username = "李大嘴" where id = '5045dfba5f5b4cb5b805c379fc123456';
    commit; 字段改变为李大嘴

    注意:
    当一个session在update操作过程中,其他session只能读操作,只能读到原来数据,写操作,会阻塞。

    delete操作:
    获取删除记录的位置,然后使用排他锁锁定该记录。

    session1 session2
    set autocommit =0;
    delete from edu_user where id = '5045dfba5f5b4cb5b805c379fc123456'; set autocommit =0;
    阻塞:delete from edu_user where id = '5045dfba5f5b4cb5b805c379fc123456';
    commit; 指定记录删除
    执行:delete from edu_user where id = '5045dfba5f5b4cb5b805c379fc123456';
    commit;

    insert操作:
    不需要加锁,通过隐式锁来保护事务全过程。
    insert操作检查:

    • 情况1:如果记录之间存在有间隙锁,那么为了避免幻读情况,是不能插入记录。
    • 情况2:如果插入记录主键冲突,也不能插入记录。
    • 其他情况:插入隐式锁。
    session1 session2
    set autocommit =0;
    insert into edu_user(id, username, password, role_id) values('1234df4446cb4cb6bc2f639830b12345','张三','123456',3); set autocommit =0;
    非阻塞:update edu_user set username= '孙中山' where id = '5045dfba5f5b4cb5b805c379fc538bcb'; 老记录
    阻塞:update edu_user set username= '孙中山' where id = '5045dfba5f5b4cb5b805c379fc538bcb';
    commit; 新增一条张三记录
    commit; 更新记录

    相关文章

      网友评论

        本文标题:mysql共享锁vs排他锁

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