看了很多文档,发现针对事务并发执行过程中的数据一致性问题,即脏读、不可重复读、幻读的解释一塌糊涂,这也不能说什么,因为官方SQL标准中的定义也模糊不清。
按照mysql中遵循的事务隔离级别,可以梳理一下其中的关系
隔离级别 | 脏读 | 不可重复读 | 幻读 | 使用到的锁 |
READ UNCOMMITTED (读未提交) | 有 | 有 | 有 | 无 |
READ COMMITTED (读已提交) | 无 | 有 | 有 | 记录锁(行级锁) |
REPEATABLE READ (可重复读,重复读一致) | 无 | 无 | 有 | 记录锁+间隙锁,俗称Next-Key锁 |
SERIALIZABLE (串行化) | 无 | 无 | 无 | 普通SELECT语句自动转为SELECT ... FOR SHARE 使用Next-Key锁 写操作加排他锁,当前事务外的其他事务想对数据进行非查询操作会锁定记录 |
看着隔离级别中的名字定义和数据一致性问题可知,针对的是事务执行过程中查询数据的问题,然而这些问题可能是由于插入、修改、删除导致的。
隔离级别从读未提交到串行化的过程中依次加强。
读未提交是一种无脑做法,就是事务未提交的数据也读取到了,按理来说单个事务执行过程中针对数据的修改当前事务没有提交的话其他事务部应该查询到。
读已提交和可重复读针对的是非活跃状态的事务,即事务已提交的数据,因为底层用到了MVCC技术,使用了innodb中数据行的隐藏数据中的trx_id,MV指的是undo log,CC指的是readview。
从读已提交命名可以得知,只是读取到了事务已提交的数据,至于当前事务在执行过程中针对同一条查询sql涉及到的数据查询多少次返回结果如何不做限制,只有一个标准,只读取事务已提交的数据。这样就会有一个问题,别的事务针对符合查询条件的数据做了修改,那查询到的数据对不上就说不明白了。
可重复读这个比较难理解,从命名上感觉就不太规范,强调的是同一条查询sql涉及到的数据不管查询多少次只返回初次查询的结果,就是咬死了只认初次查询的数据。这里回顾一下命名,应该起名重复读一致。
串行化是最不建议的隔离级别,一般不会用这个。
这样上面的脏读、不可重复读、幻读之间的区别就比较清晰了
数据一致性问题 | 说明 |
脏读 | 可以读取未提交事务的数据,应该改为未提交读 |
不可重复度 | 同一条数据在当前事务中多次读取结果可能不一致,应该改为重复读结果不一致 |
幻读 | 强调的是当前事务在执行范围查询时符合要求的数据在事务执行过程中不能进行insert或delete操作,不然会有新数据或者应该有的数据没了 |
参看文档
https://dev.mysql.com/doc/refman/8.4/en/innodb-transaction-isolation-levels.html
https://dev.mysql.com/doc/refman/8.4/en/innodb-locking.html
https://blog.csdn.net/minterdata/article/details/133084453