美文网首页Mysql
Innodb 中的事务隔离与常见问题

Innodb 中的事务隔离与常见问题

作者: 守望星空l | 来源:发表于2018-06-19 09:45 被阅读0次

    在日常开发过程中,事务是经常被使用的,然而大多数开发者并不了解事务隔离级别是什么,也不知道不同的隔离级别下使用事务时可能会发生的一些问题。

    SQL标准定义的四个隔离级别为:

    • READ UNCOMMITTED (读未提交)
    • READ COMMITTED (读已提交)
    • REPEATABLE READ (可重复读)
    • SERIALIZABLE (串行)

     

    user表

    id name money
    1 小李 1000

     

    READ UNCOMMITTED

    事务A修改了一条数据,但未提交,事务B可以读到被事务A修改的数据,存在脏读问题,同时也存在不可重复读、幻读等问题(不一一写实际例子)。

    事务A 事务B
    start TRANSACTION start TRANSACTION
    update user set name = '小明' where id = 1 -
    - select name from user where id = 1

     

    READ COMMITTED

    解决了脏读的情况,但是当事务A提交之后,事务B在一次事务内读取同一条数据会有不同的结果,存在不可重复读的问题。

    事务A 事务B
    start TRANSACTION start TRANSACTION
    update user set name = '小明' where id = 1 -
    - select name from user where id = 1
    COMMIT -
    - select name from user where id = 1

     

    REPEATABLE READ

    Mysql默认的事务隔离级别,解决了脏读、不可重复读问题,同时用
    next_key_lock 解决了幻读的问题,但是有出现更新覆盖的可能。

    事务A 事务B
    start TRANSACTION start TRANSACTION
    select money into @money from user where id = 1 select money into @money from user where id = 1
    update user set money = @money-100 where id = 1 -
    COMMIT -
    - update user set money = @money-50 where id = 1
    - COMMIT

    对应实际的业务场景,就是用户分别消费了100元和50元,2个事务都成功了,但是实际上最终账户只减少了50元。

    解决这种情况,需要在读取数据的时候加上排他锁(X锁),使2个事务变成串行操作。如下:

    事务A 事务B
    start TRANSACTION start TRANSACTION
    select money into @money from user where id = 1 for update select money into @money from user where id = 1 for update
    update user set money = @money-100 where id = 1 -
    COMMIT -
    - update user set money = @money-50 where id = 1
    - COMMIT

     

    SERIALIZABLE

    串行模式下,可以解决事务相互依赖导致的死锁问题,以及REPEATABLE READ下可能出现的更新被覆盖问题,但是由于不能同时执行2个或以上的事务,会使性能下降,所以大部分情况下不会选择此模式。

    相关文章

      网友评论

        本文标题:Innodb 中的事务隔离与常见问题

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