【MySQL】InnoDB 事务隔离 -- 【更新丢失、脏读、不可重复读、幻读】与【事务隔离】的关系

先给结论

【MySQL】InnoDB 事务隔离 -- 【更新丢失、脏读、不可重复读、幻读】与【事务隔离】的关系_第1张图片
PS:此表的“更新丢失“指回滚操作带来的丢失。

事务并发操作隐患

  • 并发操作隐患 – 更新丢失
    【MySQL】InnoDB 事务隔离 -- 【更新丢失、脏读、不可重复读、幻读】与【事务隔离】的关系_第2张图片

    存款事务的更新,由于取款事务的回滚,把存款事务的更新操作覆盖了。

  • 并发操作隐患 – 脏读
    脏读:transaction(A) update数据从data(a) -> data(b)并且not-commit,此时transaction(B)读的是 data(b)。A和B均not-commit的某一时刻,A由于某些情况rollback,数据变回data(a)。A、B之间没有通信,A无法告诉B已回滚了数据,造成B一直读的是data(a),data(a)可理解为被A弄脏了的信息,故为脏读。

    更新丢失脏读区别
    更新丢失是因为回滚直接覆盖另外一个session的提交的更新结果,脏读是因为session B 可以读到 session A
    未提交的数据,B在读数据的过程中回滚数据却不通知A。如果通知A,A未提交前把数据改过来即可。更新丢失就算回滚完后通知另一个session也没用,因为别的session已经提交。

  • 并发操作隐患 – 不可重复读
    可重复读:A update 数据从data(a) -> data(b)并且not-commit,此时B读的是 data(a)。在某一刻,A commit,B not-commit。现有应用层的逻辑:

     if ( A : update + commit 无异常) -> (B : select + commit)

    并发情况下,当A遇到如下的阻塞,导致B先去读数据,就会造成读到旧数据。A就算commit无异常,B的commit将会造成了一个预期外的结果。

    A : update +【因网络原因数据库重连,A被阻塞】 + commit 【time0 成功commit】
    ->
    B : select + commit 【time1 成功commit】
    

    在 time0 < time1 A已经commit,B读的是最新的数据,正确
    而 time0 > time1 B读到的A commit前 的数据,有隐患

    不可重复读脏读区别
    不可重复读,读的全都是已经提交的数据,若A未提交数据,则B可读到A上一次提交的数据。若A已经提交,则B可读到最新数据,就算只能读提交后的数据(避免脏读),也不能保证B读到的是最新的数据。

  • 并发操作隐患 – 幻读
    幻读:A select数据,结果集为3条数据dataCount(3),并且not-commit。此时B插入一条数据并commit导致表数据变为dataCount(4)。现有应用层的逻辑:

    A:  // A 筛选出结果集
    temp = select * from emp;  
    
    B:  // 判断完成后 B 插入一条数据
    insert into emp values ...
    
    A: // 在A的结果集对每个人都涨100块工钱
    update emp set salary = salary + 100;  
     
    // 程序计算的cost == 300, 但事实上支出为400, A看着奇怪,明明select出3条记录,为什么update成功4条记录
    cost = temp * 100

    A感知不到B插入的数据,本想更新3条数据,却更新了4条数据,称为幻读。

    不可重复读幻读 本质区别
    不可重复读是针对同一行数据,幻读是自己莫名其妙更新了自己感知不到的数据行 。

消除并发隐患 – 事务隔离助记

  • READ-UNCOMMITTED
    可以读事务未提交的数据,MySQL底层仅用于避免更新丢失

  • READ-COMMITTED
    只能读事务已提交的数据,避免了脏读

  • REPEATABLE-READ
    见面知意,可重复读提供了一种能力:重复读同一事务内的数据是一致的,用于避免 脏读不可重复读 。【读】分为 【快照读】、【当前读】
    RR如何实现同个事务中【快照读】的数据都为一致

  • SERIALIZABLE
    序列化,串行执行,是最严格的事务隔离,能避免 脏读不可重复读幻读
    SERIALIZABLE如何实现防止幻读,RR级别下通过SQL语句也能避免幻读

你可能感兴趣的:(MySQL,后端)