环境说明: mysql 5.7 + innodb引擎
1. 脏读的情况:对于两个事务A与B,B读取了已经被A更新但是还没有提交的字段之后,若此时A回滚,B读取的内容就是临时并且无效的
开启事务A 修改 id = 2 的记录
同时开启事务B 查询 id = 2 的记录
结论:事务A 更新的记录还没有提交前,事务B查询到还是被事务A更新前的数据,所以没有脏读
2. 不可重复读: 对于两个事务A和B,B读取了一个字段,然后A更新了该字段并提交之后,B再次提取同一个字段,值便不相等了。
事务A提交后
事务B再次查询得到的结果和上一次是一致的,但是经过测试,即使事务B先开启,只要事务A在事务B查询 记录1 前先提交了对 记录1 的更新,那么查询到的就会是事务A更新后的数据,事务B中对同一条数据的多次查询结果是不会因为其他事务而发生变化,除非在事务B中对数据进行修改,否则在事务B中执行的查询结果都会与第一次查询到的结果保持一致(快照读)。
结论:重复读取的结果是一致的,所以不会出现不可重复读的问题。
3. 幻读: 对于两个事务A、B,B从表中读取数据,然后A进行了INSERT操作并提交,当B再次读取的时候,结果不一致的情况发生。
开启事务A,插入一条数据,先不提交
事务B,查询时没有查询到事务A新增的记录
提交事务A
事务B,再次查询还是不会查询到事务A已经提交的记录
但当在查询语句后面加上 lock in share mode 或者 for update 就能查询到“当前读”的数据
同理经过测试,只要insert,update,delete 都是获取“当前读”数据,而不是“快照读”,关于“当前读”和“快照读”的概念可以参考mvcc的相关文章。
如果遇到其他事务对同一记录有未提交的insert,update,delete 操作,则会等待其他事务执行完毕释放锁后继续操作。例如事务A新增记录4未提交,事务B对记录4进行update,delete操作并不会立刻提示找不到记录4,而是等待事务A的执行结果,若事务A commit ,则事务B继续执行,若事务A rollback, 则事务B才会提示记录4 不存在。更新和删除操作也是如此,虽然不算脏读,但是应该算幻读了。