这可能是对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的情况下:
- 第一步:操作A的事务查询到数据X.age=20,进行更新X.age = age + 1 = 21,事务结束。
- 第二步:操作A的事务结束后,启动操作B的事务,查询到数据X.age=21,进行更新X.age = age + 1 = 22,事务结束。
- 最终结果,X.age=22
并发情况下:
- 操作A的事务查询X.age=20,进行更新X.age = age + 1 = 21,此时事务还没有提交;
- 操作B在事务A没有提交的情况下,查询X.age=20,进行更新X.age = age + 1 = 21,提交事务X.age=21
- 操作A的事务提交,X.age=21
- 最终结果X.age=21
后提交的事务将先提交的事务覆盖,这种情况就是丢失修改。
2.3. 不可重复读
场景:操作A同一次事务内执行两次uid=1的用户年龄,原始数据age=18;操作B更新uid=1的age=20
完全符合ACID的情况下:
- 操作A的事务内,连续执行两次查询,此时其它事务不允许开始,所以在此事务内不管查询多少次uid=1的age都为18,事务提交后
- 此时事务A提交,启动操作B事务,更新uid=1的age=20,提交事务。
- 操作A查询到的age=18是固定的,为正常结果
并发情况下:
- 操作A事务内,第一次查询age=18,此时操作B并发执行
- 操作B更新age=20,在操作A事务未进行第二次查询时,操作B事务提交
- 操作A此时进行事务内的第二次查询,age=20
- 同一个事务内两次查询结果不同,这种情况叫不可重复读
2.4. 幻读
场景:操作A同一个事务内两次查询age < 20的所有用户,比如为20条信息;操作B新增条用户信息,且用户age < 20
完全符合ACID的情况下:
- 操作A事务未提交前,其它事务不允许执行,所以此操作内的每次查询都为20条结果
- 操作A事务提交后,操作B执行
- 两次操作事务串行,操作结果正常
并发情况下:
- 操作A事务开启,第一次查询结果为20条
- 在操作A未进行第二次查询时,操作B事务开启,插入一条用户age<20的数据,提交事务
- 操作A进行第二次查询,结果为21条
- 此时,两次查询结果的数量不一致,好像出现了幻觉。我们把这种多次查询数据增多或减少的情况称为幻读
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的事务
标签:事务,20,age,查询,透彻,提交,MySQL,操作 来源: https://blog.csdn.net/weixin_38403680/article/details/114268805