在MySQL中,事务⽀持是在引擎层实现的,但并不是所有的引擎都⽀持事务,⽐如MySQL 原⽣的MyISAM引擎就不⽀持事务,这也是 MyISAM 被 InnoDB 取代的重要原因之⼀.
事务A | 事务B |
---|---|
启动事务 查询得到值1 | 启动事务 |
查询得到值1 | |
将1改成2 | |
查询得到值value1 | |
提交事务B | |
查询得到值value2 | |
提交事务A | |
查询得到值value3 |
在不同的隔离级别下,事务A的返回结果是不同的:
若隔离级别是“读未提交”,则 V1的值就是 2.这时候事务B虽然还没有提交,但是结果已经被A看到了.因此,V2,V3,也都是2.
若隔离级别是“读提交”,则 V1是1,V2的值是2.事务B的更新在提交后才能被A看到,所以V3的值也是2.
若隔离级别是“可重复读”,则 V1,V2是1, V3是2.之所以V2还是1,遵循的就是这个要求:事务在执⾏期间看到的数据前后必须是⼀致的。
若隔离级别是“串⾏化”,则在事务B执⾏“将1改成2”的时候,会被锁住.直到事务A提交后,事务B才可以继续执⾏.所以从 A 的⻆度看,V1,V2值是1,V3的值是2.
隔离级别的实现原理是怎样的啦?
在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑为准.在"可重复读"隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图,所以读到的数据不会发生变化.在"读提交"隔离级别下,这个视图是在每个SQL语句开始执行的时候创建的,所以在查询SQL执行前如果数据发生修改,也可以读到.而"读未提交"是直接返回记录上的最新值,没有视图概念."串行化"是直接使用加锁的方式来避免并行访问.
那么,在"可重复读"的隔离级别下,多个事务读到的数据是一样的,假设都是对某个字段做加1操作,会不会出现三个事务执行完后,最终结果只加了1而不是加3啦?其实是不会的,因为执行更新的时候我们会去记录一段回滚操作,上面记录最新值以及通过回滚操作得到前一个状态的值,所以并发更新的时候其实是可以看见别的事务做的修改的,所以不会出现修改覆盖,这个就是数据库多版本并发控制(MVCC).