MySQL 之 InnoDB引擎 Transaction(事务)

为什么需要事务?

    假设有这样一个场景,用户进行订单支付这一操作,实现的过程中我们需要像订单表中添加一条记录,并且向支付记录表中添加一条记录,我们没有开启事务,假设我们第一条SQL语句执行成功了,但是第二条SQL语句由于某原因(可能系统崩溃什么的)执行失败了,那么我们的订单表插入了一条记录,但是我们的支付记录表没有添加记录,用户在支付的记录里面找不到自己的记录,但是却有订单,这就造成了数据的不同步。

    数据库引入事务的主要目的:事务会将数据库转换成一种一致状态,在数据库提交操作的时候,确保要么所有修改都已经保存了,要么修改都不保存,也就是事务中的所有操作都执行成功方才提交操作,若中间有任何一环执行不成功,事务回滚到所有操作执行前状态。

    这样就上述的情况就可以避免数据的不同步。

 

事务定义

维基百科

MySQL 之 InnoDB引擎 Transaction(事务)_第1张图片

简述

事务是是数据库管理系统执行过程中的一个逻辑单位,并且以独立于其他事务的一致的可靠的方式进行处理。

数据库事务通常包含了一个序列的对数据库的读/写操作。包含有以下两个目的:

    1. 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。

    2. 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。

在数据库管理系统中,事务是逻辑或工作的单个单元,有时由多个操作组成。在数据库中以一致模式完成的任何逻辑计算都称为事务。

事务满足四个特性,也就是ACID。

 

 

事务的四大特性ACID

1、 原子性(Atomic)

    一个事务必须被视为一个不可分割的最小单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。

2、 一致性(Consistency)

    一致性指事务将数据库从一种状态转变为下一种一致的状态。事务开始前和结束后,数据库的完整性约束没有被破坏。一致状态的含义即数据库中数据应满足完整性约束。举个栗子,用户A和B的总资产加起来一共200元,他们之间相互转账,但不管他们怎么转账,事务结束后两人的总资产加起来应该还是200元。这就是事务的一致性。事务是一致性的单位,如果事务中某操作失败了,系统可以自动撤销事务回到初始化状态。

3、 隔离性(Isolation)

    隔离性有其他称呼如并发控制(concurrency control)、可串行化(serializability)、锁(locking)等。事务的隔离性要求每个读写事务的对象对其他事务的操作对象能相互分离,即该事务提交前对其他事物都不可见,通常使用锁来实现。当前数据库系统都提供了一种粒度锁的策略,允许事务仅锁住一个实体对象的子集,以此来提高事物之间的并发度。

4、 持久性(durability)

    事务一旦提交,其结果是永久性的。即时发生宕机数据库也能恢复。但若不是数据库本身发生故障,而是一些外部原因如RAID卡损坏等,数据可能会丢失,所以持久性保证事务系统的高可靠性(High Reliability),而不是高可用性(High Availability)。对于高可用性的实现,事务本身不能保证,需要一些系统共同配合来完成。

 

 

事务的隔离级别

 

并发事务带来的问题

在典型的应用程序中,多事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。可能会导致以下的问题:

•脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。

•丢失更新(Lost to modify):

一般分为两种

第一种:

A事务撤销时,把已经提交的B事务的更新数据覆盖了。

MySQL 之 InnoDB引擎 Transaction(事务)_第2张图片

解决:SQL92没有定义这种现象,标准定义的所有隔离级别都不允许第一类丢失更新发生。(对于这种更新丢失数据库基本已经解决了)

 

第二种:

第二种也就是我们所说的更新丢失,指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失更新。 

 

MySQL 之 InnoDB引擎 Transaction(事务)_第3张图片

 

•不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。

•幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入或删除了一些数据(记录)时。在随后的查询中,第一个事务(T1)就会发现多了或少了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

 

(不可重复读和幻读的不同:不可重复读的重点是修改,幻读的重点在于新增或者删除。例1(同样的条件, 你读取过的数据, 再次读取出来发现值不一样了 ):事务1中的A先生读取自己的工资为 1000的操作还没完成,事务2中的B先生就修改了A的工资为2000,导 致A再读自己的工资时工资变为 2000;这就是不可重复读。例2(同样的条件, 第1次和第2次读出来的记录数不一样 ):某工资单表中工资大于3000的有4人,事务1读取了所有工资大于3000的人,共查到4条记录,这时事务2 又插入了一条工资大于3000的记录,事务1再次读取时查到的记录就变为了5条,这样就导致了幻读。)

 

隔离级别

数据库定义了四个隔离级别:

•READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

•READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

•REPEATABLE-READ(可重读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

•SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

MySQL 之 InnoDB引擎 Transaction(事务)_第4张图片

稍微解释一下第二种丢失更新的情况在可重读的情况下也会出现,在这篇博客里真实的实验过http://www.04007.cn/article/348.html,其实也很好理解,可重复读保证同字段多次读取一致,事务A先开启,事务B后开启,事务B先完成,事务A没有完成,在REPEATABLE-READ状态下,不会将数据改成事务B完成的状态,还是旧的状态,当事务A完成的时候就造成了丢失更新。所以要避免更新丢失需要SERIALIZABLE级别,但很多情况考虑到效率的问题会采用别的方法避免。

* 安全性:read uncommitted < read committed < repeatable read < serializable

* 效率:read uncommitted > read committed > repeatable read > serializable

 

 

MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。

InnoDB 存储引擎在 REPEATABLE-READ(可重读)事务隔离级别下使用的是Next-Key Lock 锁算法,因此可以避免幻读的产生,这与其他数据库系统(如 SQL Server)是不同的。所以说InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读) 已经可以完全保证事务的隔离性要求,即达到了 SQL标准的SERIALIZABLE(可串行化)隔离级别。

因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是READ-COMMITTED(读取提交内容),但是要知道的是InnoDB 存储引擎默认使用 REPEATABLE-READ(可重读)并不会有任何性能损失。

InnoDB 存储引擎在 分布式事务 的情况下一般会用到SERIALIZABLE(可串行化)隔离级别。

 

 

以上是对MySQL InnoDB事务的一些粗浅认识

 

转载请注明出处:

https://blog.csdn.net/qq_36652619

你可能感兴趣的:(MySQL,InnoDB,事务,后台开发,数据库,MySQL,之,InnoDB,存储引擎浅析)