• 脏读、不可重复读、幻读、丢失更新


    根儿上来说,为什么需要事务和锁?

     如果所有的操作都是依次进行的,或者说mysql的server是单线程的,就不会有并发问题,也就不需要事务和锁了。然而事实上,是多客户端,多线程的,所有必须要考虑并发问题,数据安全问题和同步问题。

    脏读

    脏读是在(读未提交)模式下,读到其他事务尚未提交的数据,当其他事务发生回滚时,读取到的数据就不准确了。

    此处为什么是在读未提交的模式下?这是因为只有这个模式下才能读到其他事务还没有提交的数据,其他模式下不存在这个问题。

    事务1事务2
    begin
    select age from t1 where id = 1;  return 26;begin;
    update t1 set age = 27 where id = 1
    select age from t1 where id = 1;  return 27;
    rollback;

     这里事务1读到了事务2尚未提交的修改,但是事务2发生了回滚,这个时候事务1读取到的值就是脏数据,称之为脏读。

    不可重复读

    在同一个事务内,对同一条记录,前后两次读取到的值不一样,称之为不可重复读。

    不可重复读在(读未提交)(读已提交)两个模式下都存在。

    事务1事务2
    begin;
    select age from t1 where age between 10 and 30;  return 26;begin;
    update t1 set age = 27 where id = 1; commit;
    select age from t1 where id = 1;  return 27;
    commit;

    乍一看好像跟脏读差不多?其实区别在于红色的部分,那就是事务2是否提交。脏读是指这个age数据尚未提交就被读取到了,而本例中是已经提交的修改,并非脏读。而不可重复读指的是事务1中前后两次读取到的值不一样

    幻读

    幻读是不可重复读的一种特殊情况,不可重复读特别注重数据记录本身的不可复现,而幻读指数据的条数不可稳定复现。

    事务1事务2
    begin;
    select age from t1 where age between 26 and 30;  return 27;begin;
    insert into t1 (id, age) values(2, 28);   commit;
    select age from t1 where age between 26 and 30;   return [27,28];
    commit;

    在事务1的两次查询中,事务2插入了一条数据,并提交事务。而事务1第二次读取时,存在两条符合条件的数据,前后不相等。

    我们发现,脏读、不可重复读、幻读,三者均存在于“一个事务写,另外一个事务读” 的场景。

    丢失更新

    丢失更新分为两类,一类叫做回滚覆盖,一类叫做提交覆盖

     事务1首先读取到初始值1000,而期间事务2完成了 读取+更新(1100),然后事务1继续执行扣减,预期事务1应该在事务2提交的1100的基础上扣减,现在变成了基于1000扣减,相当于事务2的提交被覆盖掉了,这就是提交覆盖。

     事务1首先读取到初始值1000,而期间事务2完成了 读取+更新(1100),然后事务1发生回滚,预期事务2提交的1100会是最终的结果,现在回滚成了1000,相当于事务2的提交被回滚了,这就是回滚覆盖。

    提交覆盖是因为在两个事务同时读写数据时,一个事务执行完毕,另外一个事务基于旧数据进行操作,导致已经提交的事务的修改被抹掉了。

    四种隔离级别

    1. read uncommitted: 所有事务都可以看到其他未提交事务的执行结果。

    2. read committed: 一个事务只能看见已提交事务所做的改变。

    3. repeatable read: 确保在同一事务内相同的查询语句的执行结果一致,读到的是事务开启的那一瞬间的快照,并且是稳定的快照。

    4. serializable: 它通过强制事务排序,使之不可能相互冲突。

    在这里插入图片描述

    隔离级别/操作类型
    读未提交不加锁加行共享锁,事务结束时释放
    读已提交加行共享锁,读完释放加行互斥锁,事务结束时释放
    可重复读加行共享锁,事务结束时释放加行互斥锁,事务结束时释放
    串行化加表级共享锁,事务结束时释放加表级互斥锁,事务结束时释放

    串行化

    串行化会把所有的数据处理串行化,避免数据并发的问题。

    事务1:查询所有数据

     事务2:条件查询数据

     事务1:修改数据

     这条更新会被阻塞,因为两边的查询都会隐式加锁,排斥数据更新操作。

    可重复读

    可重复读采用gap-lock,或者next-key lock保证事务内多次读取到的数据是稳定的,与开启事务那一刻的数据状态保持一致,并不会因为其他事务的操作而发生变化。

    事务1:查询指定范围的数据

    事务2:更新此查询范围内的某条数据并提交

     事务1:再次查询,发生数据并没有发生变化

    读已提交

    读已提交模式下,每次读取到的数据是最新的快照。不可避免的出现不可重复读和幻读的问题。没有间隙锁,无法阻拦前后位置插入新的数据。

    事务1:读取到指定的记录

    事务2:更新这条数据并提交 

     事务1:再次查询,发现是更新后的数据

    读未提交

    读未提交时,不涉及到锁,因此读到的都是最新的数据,但是由于其他事务可能还没有提交就被读到了,会出现脏读。

    事务1:查询指定的数据

     事务2:修改这个数据,但是先不提交

     事务1:读取到的数据是事务2修改了的数据

  • 相关阅读:
    JavaScript事件触发
    系统架构设计专业技能 · 软件工程之UML建模设计
    Vuex与前端表格施展“组合拳”,实现大屏展示应用的交互增强
    BUUCTF·[WUSTCTF2020]大数计算·WP
    机器视觉系统的配件及工作过程
    控制反转 IOC 理论推导
    【C++】面向对象(一)
    广西建筑模板厂家批发——能强优品木业
    【微信小程序】页面事件
    POSTGRESQL中的SQL高级应用案例——等你来挑战
  • 原文地址:https://blog.csdn.net/Day_and_Night_2017/article/details/127642292