首页 > 代码库 > Mysql InnoDB事务
Mysql InnoDB事务
事务特点 ACID
ATOMICITY:原子性
一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性
CONSISTENCY:一致性
数据库总是从一个一致性的状态转换到另一个一致性的状态。
ISOLATION:隔离性
通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。
DURABILITY:持久性
一旦事务提交,则其所做的修改不会永久保存到数据库。
隔离级别:
READ UNCOMMITTED(未提交读)
在READ UNCOMMITTED级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也被称为脏读(Dirty Read)。这个级别会导致很多问题,从性能上来说,READ UNCOMMITTED不会比其他的级别好太多,但却缺乏其他级别的很多好处,除非真的有非常必要的理由,在实际应用中一般很少使用。
READ COMMITTED(提交读)
大多数数据库系统的默认隔离级别都是READ COMMTTED(但MySQL不是)。READ COMMITTED满足前面提到的隔离性的简单定义:一个事务开始时,只能"看见"已经提交的事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这个级别有时候叫做不可重复读(nonrepeatble read),因为两次执行同样的查询,可能会得到不一样的结果
REPEATABLE READ(可重复读)
REPEATABLE READ解决了脏读的问题。该隔离级别保证了在同一个事务中多次读取同样记录结果是一致的。但是理论上,可重复读隔离级别还是无法解决另外一个幻读(Phantom Read)的问题。所谓幻读,指的是当某个事务在读取某个范围内的记录时,另一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行(Phantom Row)。InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)解决了幻读的问题。
SERIALIZABLE(可串行化)
SERIALIZABLE是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。简单来说,SERIALIZABLE会在读取每一行数据都加锁,所以可能导致大量的超时和锁争用问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别。
MVCC背景:
MySQL事务默认使用REPEATABLE READ(可重复读)隔离级别。该隔离级别还是会产生幻读问题。即当某个事务读取某个范围的记录时,另外一个事物在该范围插入了新的记录,那么之前的事务再次读取该范围的记录时,会产生幻行。MySQL InnoDB就是通过多版本并发控制(MVCC)解决幻读问题。
MVCC简介:
MVCC将数据库的行锁与行的多个版本结合起来,只需要很小的开销,就可以实现非锁定读,从而大大提高数据库系统的并发性能.
MVCC实现原理:
MVCC保存某个时间点上的数据快照。一个事务内,看到的是同一个版本的快照,数据一致。不同事务在同一时间点看到的数据会不一致,因为他们得到的数据版本不一样。InnoDB在每行记录存在额外的隐藏字段,其中一列存储行被更新的版本号,另外一列存储行被删除的版本号。每当一个事务开始的时候,innodb都会给这个事务分配一个递增的版本号,所以版本号也可以被认为是事务号.对于每一个”查询”语句,innodb都会把这个查询语句的版本号同这个查询语句遇到的行的版本号进行对比,然后结合不同的事务隔离等级,来决定是否返回该行。当隔离级别是REPEATABLE READ时,这种策略下,select、delete、 insert、 update语句如何操作:
1) SELECT 对于select语句,只有同时满足了下面两个条件的行,才能被返回:
?行的被修改版本号小于或者等于该事务号
?行的被删除版本号要么没有被定义,要么大于事务的版本号:行的删除版本号如果没有被定义,说明该行没有被删除过;如果删除版本号大于当前事务的事务号,说明该行是被该事务后面启动的事务删除的,由于是repeatable read隔离等级,后开始的事务对数据的影响不应该被先开始的事务看见,所以该行应该被返回.
2) INSERT 对新插入的行,行的更新版本被修改为该事务的事务号
3) DELETE 对于删除,innodb直接把该行的被删除版本号设置为当前的事务号,相当于标记为删除,而不是实际删除
4) UPDATE 在更新行的时候,innodb会把原来的行复制一份到回滚段中,并把当前的事务号作为该行的更新版本
InnoDB存储引擎MVCC的实现策略:
在每一行数据中额外保存两个隐藏字段:当前行创建时的版本号和删除时的版本号(可能为空)。每个事务又有自己的版本号,这样事务内执行CRUD操作时,就通过版本号的比较来达到数据版本控制的目的。具体做法见下面的示意图。
MVCC缺点:
为了实现多版本,InnoDB需要维护额外的隐藏字段,以及清理不需要的行版本,带来额外开销。
验证(同时开两个终端,左边的为事物A,右边的为事物B;表数据为空)
一,事物级别为 RC
1.事物A插入(更新),事物B读取
按操作步骤执行:
我们可以得出结论
1)当事物A插入数据没有提交的时候,事物B没有查到数据(避免脏读)
2)当事物A提交事物后,事物B可以查到数据(同一个事物里边查两次结果不一致;不可重复读)
2,A事物更新,B事物也更新(删除)。
当事物A更新数据的时候,对操作行加排它锁。事物B更新此条数据的时需要等事物A提交或回滚之后才可以执行。所以是否可重复读对结果不会有影响,都需要等待事物A执行结束之后,事物B才会执行。
二,事物级别为 RR
1.事物A插入,事物B读取
我们可以得出结论
1)当事物A插入数据没有提交的时候,事物B没有查到数据(避免脏读)
2)当事物A提交事物后,事物B还是没有数据(同一个事物里边查两次结果一致;可重复读)
Mysql InnoDB事务