文章目录
1. 数据库事务概述
1.1 存储引擎支持情况
MySQL数据库SHOW ENGINES
命令来查看当前 MySQL 支持的存储引擎都有哪些,以及这些存储引擎是否支持。
由此能看出在 MySQL 中,只有InnoDB 是支持事务的。
1.2 基本概念
事务: 一组逻辑操作单元,使数据从一种状态变换到另一种状态。
事务处理的原则: 保证所有事务都作为 一个工作单元
来执行,即使出现了故障,都不能改变这种执行方 式。当在一个事务中执行多个操作时,要么所有的事务都被提交( commit
),那么这些修改就 永久
地保 存下来
;要么数据库管理系统将 放弃
所作的所有 修改
,整个事务回滚( rollback )到最初状态。
# 案例:AA用户给BB用户转账100
update account set money = money - 100 where name = 'AA';
# 服务器宕机
update account set money = money + 100 where name = 'BB';
1.3 事务的ACID特性
原子性(atomicity):
原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。即要么转账成功,要么转账失败,是不存在中间的状态。如果无法保证原子性会怎么样?就会出现数据不一致的情形,A账户减去100元,而B账户增加100元操作失败,系统将无故丢失100元。原子英文单词的意思就有不可分割的意思,古时候西方人存在一个不可分割的基本单位构成了宇宙上的所有物质,古希腊哲学家德谟克利特便是原子论的代表人物,但是后来科学的发现,原子并不是构成物质的最小单位。
一致性(consistency):
(国内很多网站上对一致性的阐述有误,具体你可以参考 Wikipedia 对Consistency的阐述)
根据定义,一致性是指事务执行前后,数据从一个 合法性状态
变换到另外一个 合法性状态
。这种状态是 语义上
的而不是语法上的,跟具体的业务有关。
那什么是合法的数据状态呢?满足 预定的约束
的状态就叫做合法的状态。通俗一点,这状态是由你自己来定义的(比如满足现实世界中的约束)。满足这个状态,数据就是一致的,不满足这个状态,数据就 是不一致的!如果事务中的某个操作失败了,系统就会自动撤销当前正在执行的事务,返回到事务操作 之前的状态。
举例1: A账户有200元,转账300元出去,此时A账户余额为-100元。你自然就发现此时数据是不一致的,为什么呢?因为你定义了一个状态,余额这列必须>=0。
举例2: A账户有200元,转账50元给B账户,A账户的钱扣了,但是B账户因为各种意外,余额并没有增加。你也知道此时的数据是不一致的,为什么呢?因为你定义了一个状态,要求A+B的总余额必须不变。
举例3: 在数据表中我们将姓名
字段设置为唯一性约束
,这时当事务进行提交或者事务发生回滚的时候,如果数据表的姓名不唯一,就破坏了事务的一致性要求。
隔离型(isolation):
事务的隔离性是指一个事务的执行不能被其他事务干扰
,即一个事务内部的操作及使用的数据对并发
的其他事务是隔离的,并发执行的各个事务之间不能相互干扰。
如果无法保证隔离性会怎么样?假设A账户有200元,B账户0元。A账户往B账户转账两次,每次金额为50 元,分别在两个事务中执行。如果无法保证隔离性,会出现下面的情形:
UPDATE accounts SET money = money - 50 WHERE NAME = 'AA';
UPDATE accounts SET money = money + 50 WHERE NAME = 'BB';
1.4 事务的状态
我们现在知道 事务
是一个抽象的概念,它其实对应着一个或多个数据库操作,MySQL根据这些操作所执 行的不同阶段把 事务
大致划分成几个状态:
-
活动的(active)
事务对应的数据库操作正在执行过程中时,我们就说该事务处在活动的
状态。 -
部分提交的(partially committed)
当事务中的最后一个操作执行完成,但由于操作都在内存中执行,所造成的影响并没有刷新到磁盘
时,我们就说该事务处在部分提交的
状态。 -
失败的(failed)
当事务处在活动的
或者 部分提交的 状态时,可能遇到了某些错误(数据库自身的错误、操作系统 错误或者直接断电等)而无法继续执行,或者人为的停止当前事务的执行,我们就说该事务处在 失 败的 状态。 -
中止的(aborted)
如果事务执行了一部分而变为失败的
状态,那么就需要把已经修改的事务中的操作还原到事务执 行前的状态。换句话说,就是要撤销失败事务对当前数据库造成的影响。我们把这个撤销的过程称之为回滚
。当回滚
操作执行完毕时,也就是数据库恢复到了执行事务之前的状态,我们就说该事 务处在了中止的
状态。
举例:UPDATE accounts SET money = money - 50 WHERE NAME = 'AA'; UPDATE accounts SET money = money + 50 WHERE NAME = 'BB';
-
提交的(committed)
当一个处在部分提交的
状态的事务将修改过的数据都同步到磁盘
上之后,我们就可以说该事务处在了提交的
状态。
一个基本的状态转换图如下所示:
图中可见,只有当事务处于提交的
或者中止的
状态时,一个事务的生命周期才算是结束了。对于已经提交的事务来说,该事务对数据库所做的修改将永久生效,对于处于中止状态的事务,该事务对数据库所做的所有修改都会被回滚到没执行该事务之前的状态。
2. 如何使用事务
使用事务有两种方式,分别为 显式事务
和 隐式事务
。
2.1 显式事务
步骤1: START TRANSACTION 或者 BEGIN ,作用是显式开启一个事务。
mysql> BEGIN;
#或者
mysql> START TRANSACTION;
START TRANSACTION
语句相较于 BEGIN
特别之处在于,后边能跟随几个 修饰符
:
① READ ONLY
:标识当前事务是一个 只读事务