这可能是对MySQL事务讲的最透彻的文章了

在这里插入图片描述

1. 什么是ACID

  • 原子性(Atomicity): 事务是最小的执行单位,不允许分隔。事务的原子性确保动作要么全部完成,要么完全不起作用
  • 一致性(Consistency): 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的
  • 隔离性(Isolation): 并发访问数据库时,一个用户的事务不被其他事务所干扰,个并发事务之间数据库是独立的
  • 持久性(Durability): 一个事务被提交之后,它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响

2. 并发造成的问题

2.1. 脏读

场景:两个操作同时到达数据库,操作A为查询数据X的age;操作B为更新数据X的age

完全符合ACID的情况下:

这种情况下,操作A和操作B的事务是串行化的,要么先执行操作A,要么先执行操作B,事务没有交叉,一切正常。


并发情况下:

当操作B的事务对数据X进行了修改,但事务还没有提交的同时,操作A开始查询数据X,得到查询结果后,操作B的事务完成了提交。此时,事务B查询的数据是过时的,这种情况就叫做脏读

2.2. 丢失修改

场景: 操作A和操作B同时查询{id=1,age=20}的数据X,并对age进行+1操作

完全符合ACID的情况下:

  1. 第一步:操作A的事务查询到数据X.age=20,进行更新X.age = age + 1 = 21,事务结束。
  2. 第二步:操作A的事务结束后,启动操作B的事务,查询到数据X.age=21,进行更新X.age = age + 1 = 22,事务结束。
  3. 最终结果,X.age=22

并发情况下:

  1. 操作A的事务查询X.age=20,进行更新X.age = age + 1 = 21,此时事务还没有提交;
  2. 操作B在事务A没有提交的情况下,查询X.age=20,进行更新X.age = age + 1 = 21,提交事务X.age=21
  3. 操作A的事务提交,X.age=21
  4. 最终结果X.age=21

后提交的事务将先提交的事务覆盖,这种情况就是丢失修改

2.3. 不可重复读

场景:操作A同一次事务内执行两次uid=1的用户年龄,原始数据age=18;操作B更新uid=1的age=20

完全符合ACID的情况下:

  1. 操作A的事务内,连续执行两次查询,此时其它事务不允许开始,所以在此事务内不管查询多少次uid=1的age都为18,事务提交后
  2. 此时事务A提交,启动操作B事务,更新uid=1的age=20,提交事务。
  3. 操作A查询到的age=18是固定的,为正常结果

并发情况下:

  1. 操作A事务内,第一次查询age=18,此时操作B并发执行
  2. 操作B更新age=20,在操作A事务未进行第二次查询时,操作B事务提交
  3. 操作A此时进行事务内的第二次查询,age=20
  4. 同一个事务内两次查询结果不同,这种情况叫不可重复读

2.4. 幻读

场景:操作A同一个事务内两次查询age < 20的所有用户,比如为20条信息;操作B新增条用户信息,且用户age < 20

完全符合ACID的情况下:

  1. 操作A事务未提交前,其它事务不允许执行,所以此操作内的每次查询都为20条结果
  2. 操作A事务提交后,操作B执行
  3. 两次操作事务串行,操作结果正常

并发情况下:

  1. 操作A事务开启,第一次查询结果为20条
  2. 在操作A未进行第二次查询时,操作B事务开启,插入一条用户age<20的数据,提交事务
  3. 操作A进行第二次查询,结果为21条
  4. 此时,两次查询结果的数量不一致,好像出现了幻觉。我们把这种多次查询数据增多或减少的情况称为幻读

2.5. 脏读和不可重复的区别

这两种情况十分类似,可以这样理解:

  • 脏读: 在一次事务内,只进行一次查询,查询时数据发生了改变,此事务不知道它查询的数据已经发生了变化,这种叫脏读
  • 不可重复读: 在一次事务内,进行多次查询的过程中,此事务知道查询的数据有变化,这种叫不可重复读

主要区别就在于是一次查询,还是多次查询

3. MySQL的隔离级别

  • READ-UNCOMMITTED(读取未提交): 最低隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读、不可重复读
  • READ-COMMITTED(读取已提交): 允许读取并发事务已提交的数据,可以阻止脏读,但是幻读、不可重复读仍有可能发生
    • 两个事务,其中一个事务没有提交的话,另一个事务是没办法读取的,所以可以避免脏读
    • 两个事务,事务A中,第一次读取多条信息时,事务B还没有提交;事务B提交后,事务A进行了第二次查询,可能会查询到事务B提交的数据;如果事务B是插入操作,则是幻读;如果事务B是更新操作,则是不可重复读
  • REPEATABLE-READ(可重复读): 对同一个字段多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍可能发生
    • 两个事务,事务A中,第一次查询到多条数据,事务B可以是插入或更新;如果事务B是更新,由于数据不是被本身事务修改的,所以不会有脏读和不可重复读;如果事务B是插入,仍会被事务A查询到,造成幻读
  • SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有事务串行化依次执行,事务之间完全不可能产生干扰,该级别可以防止脏读、不可重复读和幻读。

4. 最后

面试官: 请讲一下MySQL的事务

猜你喜欢

转载自blog.csdn.net/weixin_38403680/article/details/114268805