"事务"了解一下
事务的四大特性
事务的四大特性是老生常谈的问题了:依次是A(原子性)、C(一致性)、I(隔离性)、D(持久性)。
- 原子性:事务不可拆分,要么全部成功,要么全部失败
- 一致性:事务对数据库的改变要符合一致性,例如转账,一个账户的增加就要伴随一个账户的减少。
- 隔离性:事务之间相互隔离,事务拥有不同的事务隔离级别。
- 持久性:事务一旦commit就不可回滚。
不同的隔离级别带来的问题
脏读
A事务读到了回滚的B事务修改的数据。即B事务修改了数据,这个时候A事务读到了修改的数据,但是B事务这个时候回滚了。A事务读到的数据就是脏数据,称为脏读。
不可重复读
就是一个事务 多次读数据发现读到的结果不一致,因为再事务执行的时候其他事务修改了数据。
幻读
即某个事务对某个范围内的数据进行修改,但是其他事务中间插入了一行数据,这个时候就会出现幻影行,称为幻读。
事务的隔离级别
事务存在四种隔离级别:读已提交,读未提交,可重复读,串行化。
读未提交
这种事务隔离级别指的是事务的每一步改变对于其他事务都是可见的,这种隔离级别的隔离性最弱,一般使用的比较少。三种情况都不可避免。
读已提交
这种事务隔离级别指的是事务对数据的修改只有提交后才对其他事务可见,这种级别解决了脏读问题,但是却没有解决不可重复读和幻读的问题。
可重复读
这种事务隔离级别指的是事务执行期间看到的数据库视图和开始看到的视图总是一致的。可以解决脏读和不可重复度的问题,但是无法解决幻读的问题,但是InnoDB引擎采用了MVCC来解决了这个问题。这也是Mysql默认的事务隔离机制。
串行化
串行化是一种强制的加锁策略,即读加读锁,写加写锁。当出现读写冲突的时候,后访问的事务必须等到前一个事务释放锁,才能继续执行。可以解读脏读、不可重复读以及幻读的问题。
事务隔离级别的实现——MVCC
MVCC是什么
在Mysql中,每个记录在进行更新的时候会同时记录一条回滚操作,一个数据会保存多个版本,这就是数据库的(多版本并发控制)MVCC。在高性能Mysql这本书里面有提到,MVCC实现的是,相同事务不同时刻看到的数据库一致,不同事务在相同时刻看到的数据库不一致。MVCC不是Mysql独有的,Orcale和SQL Server也支持MVCC。
实现方式
MVCC是在可重复读和读已提交中使用的技术。其中采用了视图的概念来支持MVCC的实现。对于读已提交来说使用的是当前操作的视图,对于可重复读来讲,使用的是事务开始的时候的视图。
这里以InnoDB为例,InnoDB采用了快照来实现MVCC,即为每行的数据增加两个默认字段,一个是创建时间,另外一个是删除时间。每次数据库进行改变的时候都只会改变当前版本之前的数据。同时使用了GAP锁来时解决了幻读问题。
GAP锁是什么
GAP锁又称间隙锁,是InnoDB引擎用来解决幻读问题的锁。即在两个数据之间进行加锁,例如Mysql中有3条数据那么就会加上四个就间隙锁,因为存在四个间隙(两端的也算)。同时GAP锁和右侧相邻的行锁构成next-key锁,next-key锁是左开右闭的。同时GAP锁之和向这个GAP中插入数据这件事情冲突,和其他的GAP锁把并不冲突。
InnoDB的加锁规则
InnoDB只会对查找过程中访问的数据进行加锁,加锁的力度默认是next-key,前开后闭。当是索引上的等值查询的时候,给唯一索引加锁时,会退化为行锁,而向右遍历到最后一个不满足条件的值的时候next-key锁退化为GAP锁。
MVCC的缺点
由于MVCC会找合适的数据版本,所以可能还会导致版本号过多的情况下数据库的数据版本过多情况下SQL变慢。