1. 数据库事务概述
事务是数据库区别于文件系统的重要特性之一,当我们有了事务就会让数据库始终保持一致性,同时我们还能通过事务的机制恢复到某个时间点,这样可以保证给已提交到数据库的修改不会因为系统崩溃而丢失。
1.1 基本概念
事务:一组逻辑操作单元,使数据从一种状态变换到另一个状态。
事务处理的原则:保证所有事务都作为一个工作单元来执行,即使出了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事物都被提交(commit),那么这么修改都被永久的保存下来;要么数据库管理系统将放弃所作的所有修改,整个事物回滚到(rollback)到最初状态。
案例:
# AA给BB转账100元
update account set money = money - 100 where name = 'AA';
# 服务器故障
update account set money = money + 100 where name = 'BB';
1.2 事物的ACID特性
1). 原子性(atomicity):
原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。即要么转账成功,要么转账失败,是不存在中间的状态。如果无法保证原子性会怎么样?就会出现数据不一致的情形。A账户减去100元,而B账户增加100元操作失败,系统将无故丢失100元。
2). 一致性(consistency):
根据定义,一致性是指事务执行前后,数据从一个合法性状态变换到另外一个合法性状态。这种状态是语义上 的而不是语法上的,跟具体的业务有关。
那什么是合法的数据状态呢?满足预定的约束的状态叫合法的状态。通俗一点,这状态是由你自己来定义的(比如满足现实世界的约束)。满足这个状态,数据就是一致的,不满足这个状态,数据就是不一致的。如果事务的某个操作失败了,系统就会自动撤销当前正在执行的事务,返回到事务操作之前的状态。
举例:在数据表中我们将姓名字段设置为唯一性约束,这时当事务进行提交或者事务发生回滚时,如果数据表的姓名不唯一,就破坏了事务的一致性要求。
3). 隔离性(isolation):
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能相互干扰。
4). 持久性(durability):
持久性是指一个事务一旦被提交了,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
持久性是通过事务日志来保证的。日志包括了重做日志和回滚日志。当我们通过事务对数据进行修改时,首先先将数据库的变化记录到重做日志,然后再对数据库中对应的行进行修改。这样做的好处是,即使数据库系统崩溃,数据库重启后也能找到没有更新到数据库系统中的重做日志,重新执行,从而使事务具有持久性。
1.3 事务的状态
我们现在知道事务是一个抽象的概念,它其实对应着一个或多个数据库操作,MySQL根据这些擦操作所执行的不同阶段把事务分成几个状态:
- 活动的(active):事务对应的数据库操作正在执行中时,我们就说该事务处于活动的状态。
- 部分提交的(partially committed):当事务中的最后一个操作执行完成时,但由于操作都在内存层面上执行,所造成的影响并没有刷新到磁盘上,我们说该事务处于部分提交的状态。
- 失败的(failed):当事务处于活动的或者部分提交的状态时,可能遇到了某些错误(数据库自身的错误,操作系统错误或者直接断电等)而无法继续执行,或者人为的停止当前事务的执行,我们就说该事务处于失败的状态。
- 中止的(aborted):如果事务执行的一部分变为失败的状态,那么就需要把已经修改的事务中的操作还原到事务执行前的状态。换句话说,就是要撤销失败事务对当前数据库造成的影响。我们把这个撤销的过程称之为回滚。当归滚操作shiwu执行完毕时,也就是数据库恢复到了执行事务的阶段之前的状态时,我们就说该事务处于终止的状态。
- 提交的(committed)当一个处在部分提交的状态的事务将修改过的数据都同步到磁盘上之后,我们就说该事务处在了提交的状态。
一个基本的状态转换图如下:
图中可见,只有当事务处于提交的或者中止的状态时,一个事务的生命周期才算结束了。对于已经提交的事务来说,该事务对数据库所做的修改将永久生效,对于处在中止状态的事务,该事务对数据库所做的修改都会被回滚到没执行该事务之前的状态。