数据库并发的对同一批数据进行增删改,就可能会出现我们所说的脏写、脏读、不可重复读、幻读等一系列问题。MySQL提供了一系列机制来解决事务并发问题,比如事务隔离、锁机制、MVCC多版本并发控制机制。今天来探究一下事务隔离机制。
事务是一组原子性的SQL操作。 简单一点来说,一个事务内包含的所有sql语句执行才会成功,只要有任意一条没有成功则失败。要么全部成功,要么全部失败。下述案例很好的说明了事务。
张三给李四转账200:
1,检查张三余额是否高于等于200
2,从张三账户扣除200
3,给李四账户添加200
这三个步骤包含在一个事务当中,只有都满足才能满足此次转账。如果任意一步没有成功,则需要全部回滚。
原子性(atomicity):一个事务是最小工作单位,要么全部成功,要么全部失败。
一致性(consistency):即确保每次操作以后的状态要保持一致,比如张三扣了200,那么李四必定要加上200
隔离性(isolation):一个事务的执行不能被其它事务影响。比如张三转了200给李四,在此次转账事务没有完成之前,实际查询张三的余额还是没有变化。
持久性(durability):一旦事务执行提交,该执行结果就会永久保存在数据库,即时系统崩溃也不会丢失。
这就是常说的ACID特性,数据库通过该特性来确保事务正确的执行。
在ACID特性中提到了隔离性,隔离性的实现比价复杂。数据库的事务隔离级别有4个,从低到高依次为:
读未提交(read uncommitted):在此级别,A事务可以读取到B事务未提交的数据,这种情况称之为脏读(Dirty Read),实际使用极少使用。
读已提交(read committed):在此级别,A事务只能读取到B事务已经提交的数据。即B事务提交之前所做的修改A事务都是不能读取到,因此在B事务提交前后的数据可能会不一致,因此此级别也叫不可重复读。
可重复读(repeatable read):在此级别,解决了上述两个级别的问题,保证每次读取的结果是一致的。但是会出现幻读的情况,MySQL默认是此级别,但是它通过了多版本并发控制-MVCC(Multiversion Concurrency Control)解决了幻读问题。
可串行化(serializable):在此级别,通过锁解决了幻读问题。但是效率极其低下,只有在数据一致性要求极高并且对并发要求不高的情况下才会用到。
MySQL默认是使用自动提交模式,可以使用start transaction来开启事务。
MySQL现在默认使用的存储引擎是InnoDB,在InnoDB中使用MVCC来解决事务的隔离级别。MVCC可以看成行级锁的变种。并且MVCC只在可重复读与读已提交两个级别生效。
InnoDB在每行记录都添加了三个隐藏字段:
DB_ROW_ID–6字节:行标识
DB_TRX_ID–6字节:新增跟更新行的最后一个事务的事务ID,自动递增(创建版本号)
DB_ROLL_PTR–7字节:回滚指针(删除版本号)
MVCC只能查到创建时间小于等于当前事务ID的数据,以及删除版本大于当前事务ID的行,通过该控制从而达到了在可重复度级别下解决了幻读。
MVCC只能查到创建时间小于等于当前事务ID的数据,以及删除版本大于当前事务ID的行,通过该控制从而达到了在可重复度级别下解决了幻读。