美文网首页
终极篇-mysql事务隔离知识

终极篇-mysql事务隔离知识

作者: 长腿小西瓜 | 来源:发表于2018-01-19 10:42 被阅读70次

    1 基础知识

    1.1 事务ACID

    1.1.1 原子性

    整个事务要么全部成功,要么全部失败。</br>
    银行转账的梗,张三转账给李四1000元:

    • 李四账户+1000;
    • 张三账户-1000;
      上面事务的两个动作必须全部成功,全部失败。
      </br>

    扩展阅读:
    对InnoDB来说,只要client收到server发送过来的commit成功报文,那么这个事务一定是成功的。如果收到的是rollback的成功报文,那么整个事务的所有操作一定都要被回滚掉,就好像什么都没执行过一样。另外,如果连接中途断开或者server crash事务也要保证会滚掉。InnoDB通过undolog保证rollback的时候能找到之前的数据。

    1.1.2 一致性

    指的是在任何时刻,包括数据库正常提供服务的时候,数据库从异常中恢复过来的时候,数据都是一致的,保证不会读到中间状态的数据。一致性和原子性往往形影不离。</br>
    比如上面的例子:

    • 无论转账多少次,张三和李四账户余额的总和不会发生变化。
    • 结果必须是使数据库从一个一致性状态变到另一个一致性状态。

    扩展阅读:
    在InnoDB中,主要通过crash recovery和double write buffer的机制保证数据的一致性。

    1.1.3 隔离性

    指的是多个事务可以同时对数据进行修改,但是相互不影响。</br>
    要点:

    • 不能产生脏数据

    扩展阅读:
    InnoDB中,依据不同的业务场景,有四种隔离级别可以选择。默认是RR隔离级别,因为相比于RC,InnoDB的RR性能更加好。

    1.1.4 持久化

    指的是事务commit的数据在任何情况下都不能丢。</br>

    • 这里应该还包括rollback的数据也不能丢失

    扩展阅读:
    在内部实现中,InnoDB通过redolog保证已经commit的数据一定不会丢失。

    2 隔离性

    2.1 事务引发的问题

    2.1.1 脏读

    读取到其他事务尚未提交的信息。

    比如上面转账事务还没提交,这时,李四去查询自己的账号,发现多出了1000元。
    如果,转账事务回滚,那么李四再次查询发现钱又没了。
    

    2.1.2 不可重复度

    一个事务内两次读取,内容不一样,本质是读读的问题。

    2.1.3 幻读

    一个事务内,先读出某条记录,发现不存在,然后做写的操作,到提交时,却报主键冲突。这是一个读写的问题。

    典型例子:账号(唯一索引)注册
    A用户用账号:zhangjianhua,进行注册。
    B用户也用账号:zhangjianhua,进行注册。
    俩人同时提交,服务端代码的逻辑,一般是,先查询这个账号存不存在,不存在就新增:
    
    1.   begin transaction;
    2.   select count(1) from user where account='zhangjianhua';
    3.   if count(1) = 0 {
           insert into user(account) values('zhangjianhua');}
    4.   commit;
    

    假如A用户和B用户的事务都同时执行完第2步的查询,发现没这个人,A先第3步插入,紧接着A事务提交。B事务继续执行插入操作,提交。这时B报错。
    那B就觉得很奇怪,明明查询zhangjianhua是不存在的啊,为什么会保存不了。(还有一种情况:A事务插入后,没提交,B事务执行插入,这时B事务会挂起,直到A事务提交完毕,才报错)

    上面的问题:实际就是不可重复读。实际开发中也不需要规避这种问题。下面我会说明。

    2.2 事务隔离级别

    mysql默认有四种隔离级别:

    • READ-UNCOMMITTED
    • READ-COMMITTED
    • REPEATABLE-READ
    • SERIALIZABLE

    扩展阅读:

    mysql隔离级别

    MySQL Glossary

    2.2.1 READ-UNCOMMITTED

    未提交读:读取其它事务尚未提交的数据。显然这种隔离级别会导致脏读。

    2.2.2 READ-COMMITTED

    提交读,也就是大家常说的RC读(oracle隔离级别之一):读取其他事务提交后的数据。这种隔离级别可以避免脏读,但是会发生不可重复度。
    第一个事务第一次读取后,其他事务提交了第一个事务范围内的数据。第一个事务第二次读取发现数据不一致。

    2.3.3 REPEATABLE-READ

    重复读,即RR读:可同时规避脏读,重复读。但是不能规避幻读。

    2.3.4 SERIALIZABLE

    可串行化(oracle隔离级别之二): 可防止脏读、不可重复度、幻读。代价很高。

    相关文章

      网友评论

          本文标题:终极篇-mysql事务隔离知识

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