Mysql在并发时,多个事务之间会存在一些问题,脏读、不可重复读、幻读。

脏读

Mysql 脏读

脏读是指事务A读取到了事务B没有提交的数据,但是事务B回滚了,那么此时事务A读取的数据是数据库不存在的,这个时候的数据则称之为脏数据,也就是脏读。

在上面的例子的流程中,

  1. 事务B开启事务
  2. 事务B执行了一条语句 update user set name='测试' where id=2
  3. 事务A读物id=2
  4. 事务B回滚

事务B最终获取到的id=2 user数据不是数据库中存在的数据。

不可重复读

Mysql 脏读、不可重复读、幻读

不可重复读的意思是事务A在一个事务内 第一次读取的数据和第二次读取的数据不一致

在上面的例子流程中:

  1. 事务A开启事务
  2. 事务A第一次读取id=2
  3. 事务B对id=2进行的update操作并提交
  4. 事务A第二次读取id=2

这样事务A两次查找id=2的结果不一样。

幻读

幻读是指数据库在可以重复读的情况下发生的问题。

幻读,并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。
更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。

Mysql 幻读

上图中大致意思是A事务在插入前先判断是否存在id=2的数据

  1. 事务A开启事务
  2. 事务A第一次查询id=2
  3. 事务B新增id=2的数据并提交
  4. 事务A第二次读取id=2(事务满足可重复读,此时数据库不存在id=2的数据)
  5. 事务A也新增id=2的数据
  6. 事务A提交事务报错

在它两次查询数据库中没有id=2的数据的时候进行新增发现报错,感觉跟幻觉一样。

事务的隔离级别

MySQL 里有四个隔离级别:Read uncommttied(可以读取未提交数据)、Read committed(可以读取已提交数据)、Repeatable read(可重复读)、Serializable(可串行化)。

其中最后一个的隔离级别最高,第一个隔离级别最低,隔离级别越高系统付出的代价越大,并发的问题就越小。
在 InnoDB 中,默认为 Repeatable read级别,可重复读,InnoDB 中使用一种被称为 next-key locking 的策略来避免幻读(phantom)现象的产生。
使用 select @@tx_isolation; 可以查看 MySQL 默认的事务隔离级别。

隔离级别脏读不可重复读幻读
READ-UNCOMMITTED(可以读取未提交数据)
READ-COMMITTED(可以读取已提交数据)×
REPEATABLE-READ(可以重复读)××
SERIALIZABLE(可串行化)×××