数据库事务的ACID及隔离级别
Mysql中的存储引擎
在mysql5.5后MySQL5.5以后默认使用InnoDB存储引擎,除InnoDB和BDB提供事务安全表,其它存储引擎都是非事务安全表。
Mysql中的部分存储引擎特性
本次主要介绍数据库事务的ACID及隔离级别
一.事务(Transaction)
(1)ACID
事务是一组SQL语句组成的逻辑处理单元,事物具有以下4个属性,通常称为事物的ACID属性
原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么一次全都执行成功,要么全都失败回滚。只有当事务中的所有部分都成功执行了,才将事务写入磁盘并使变化永久化。
一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,所有的内部数据结构(如B+Tree索引)也都必须是正确的。
隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
(2)并发处理事任务出现的问题
相对于串行处理来说,并发事务处理能大大增加数据库资源的利用率,提高数据库系统的事务吞吐量,从而可以支持更多的用户。但并发事务处理也会带来一些问题,主要包括以下几种情况。
脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做"脏读"。
eg:A转账给B准备转2000,但是A错填了3000但是未提交这个事务,这时B查看账户发现账户增加了3000,这时A发现填错了马上撤回了这个事务,改为2000并提交了这个事务。B以为A多转了于是给A回转了1000,最终B发现账户只多了1000。
不可重复读(Non-Repeatable Reads):一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做“不可重复读”。
eg:A查看看账户发现钱足够于是准备买一个东西,正在网上转账的时候,这个时候拿着A银行卡的B 将银行卡中的钱取了出来。A出现了余额不足转账失败的情况
幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。
eg:A购物转账的时候,B查看了A的消费记录有n条,在打印的时候发现有n+1条消费记录(B的查看和打印属于同一个事物)
脏读,不可重复读和幻读的区别:
脏读:针对未提交数据
不可重复读:针对其他提交前后,读取数据本身的对比
幻读:针对其他提交前后,读取数据条数的对比
二.事务隔离性的4个级别
在上面讲到的并发事务处理带来的问题中,但防止更新丢失,并不能单靠数据库事务控制器来解决,需要应用程序对要更新的数据加必要的锁来解决,因此,防止更新丢失应该是应用的责任。
“脏读”、“不可重复读”和“幻读”,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。数据库实现事务隔离的方式,基本上可分为以下两种。
一种是在读取数据前,对其加锁,阻止其他事务对数据进行修改。
另一种是不用加任何锁,通过一定机制生成一个数据请求时间点的一致性数据快照(Snapshot),并用这个快照来提供一定级别(语句级或事务级)的一致性读取。从用户的角度来看,好象是数据库可以提供同一数据的多个版本,因此,这种技术叫做数据多版本并发控制(MultiVersion Concurrency Control,简称MVCC或MCC),也经常称为多版本数据库。
数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用对“不可重复读”和“幻读”并不敏感,可能更关心数据并发访问的能力。
为了解决“隔离”与“并发”的矛盾,ISO/ANSI SQL92定义了4个事务隔离级别,每个级别的隔离程度不同,允许出现的副作用也不同,应用可以根据自己的业务逻辑要求,通过选择不同的隔离级别来平衡“隔离”与“并发”的矛盾。表20-5很好地概括了这4个隔离级别的特性。
Mysql的默认隔离级别为Repeatable read
以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。
领取专属 10元无门槛券
私享最新 技术干货