1. 什么是ACID
- 原子性(Atomicity): 事务是最小的执行单位,不容许分隔。事务的原子性确保动做要么所有完成,要么彻底不起做用
- 一致性(Consistency): 执行事务先后,数据保持一致,多个事务对同一个数据读取的结果是相同的
- 隔离性(Isolation): 并发访问数据库时,一个用户的事务不被其余事务所干扰,个并发事务之间数据库是独立的
- 持久性(Durability): 一个事务被提交以后,它对数据库中数据的改变是持久的,即便数据库发生故障也不该该对其有任何影响
2. 并发形成的问题
2.1. 脏读
场景:两个操做同时到达数据库,操做A为查询数据X的age;操做B为更新数据X的age面试
彻底符合ACID的状况下:数据库
这种状况下,操做A和操做B的事务是串行化的,要么先执行操做A,要么先执行操做B,事务没有交叉,一切正常。markdown
并发状况下:并发
当操做B的事务对数据X进行了修改,但事务尚未提交的同时,操做A开始查询数据X,获得查询结果后,操做B的事务完成了提交。此时,事务A查询的数据是过期的,这种状况就叫作脏读。ui
2.2. 丢失修改
场景: 操做A和操做B同时查询{id=1,age=20}的数据X,并对age进行+1操做spa
彻底符合ACID的状况下:code
- 第一步:操做A的事务查询到数据X.age=20,进行更新X.age = age + 1 = 21,事务结束。
- 第二步:操做A的事务结束后,启动操做B的事务,查询到数据X.age=21,进行更新X.age = age + 1 = 22,事务结束。
- 最终结果,X.age=22
并发状况下:orm
- 操做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=20ci
彻底符合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的隔离级别。全部事务串行化依次执行,事务之间彻底不可能产生干扰,该级别能够防止脏读、不可重复读和幻读。
MySQL InnoDB 存储引擎的默认⽀持的隔离级别是 REPEATABLE-READ(可重复读)
4. 最后
面试官: 请讲一下MySQL的事务
