事务
1. 为什么要有事务
事务的存在是为了保证数据的一致性与完整性。
数据库作为保存数据的组建,很重要的要求,就是要在数据变动的过程中,保证数据的一致性与完整性:
- 一致性:数据变动前后,数据的状态要满足业务逻辑的要求,如银行转账时,账户 A 向 B 转账,A 减少的余额应该与 B 增加的余额相同,且不能大于 A 现有的余额。
- 完整性:数据变动前后,数据的状态要满足预定的约束条件,如主键约束、外键约束等。
为了保证这两个特性,数据库引入了事务的概念。
2. 事务的定义
事务(Transaction)是包含一系列操作的数据库执行单元,这些操作要么全部执行成功,要么全部执行失败。不存在中间状态。
还是转账的例子,假设账户 A 向账户 B 转账,需要执行以下操作:
- 检查账户 A 的余额是否足够
- 如果足够,从账户 A 中减去相应的金额
- 将相应的金额加到账户 B 中
在执行实际的数据变动时,这些操作就应该放到同一个事务中执行。
3. 事务的特性 - ACID
事务具备了 ACID 的特性,用来保证数据的一致性与完整性。这四个特性分别是:
- Atomicity 原子性:事务中的所有操作要么全部执行成功,要么全部执行失败。
- Consistency 一致性:事务在执行前后,数据始终保持在正确的状态,既要满足业务逻辑,也需要满足数据库的约束条件。
- Isolation 隔离性:事务在执行过程中,其他事务的执行不会影响当前事务。
- Durability 持久性:事务执行完成后,对数据库会产生永久的改变,数据的状态会持久化到磁盘上。
事务有四个重要的特性,用以保障数据的一致性与完整性,
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
下面来分别解释一下这四个特性。
3.1. 原子性 Atomicity
原子性要求事务中的所有操作要么全部执行成功,要么全部执行失败。
典型的案例就是转账操作,账户 A 向账户 B 转账,「A 的余额减少」与「B 的余额增加」是两个需要同时执行的操作,如果只执行了其中一个,那么余额就会出现混乱。
在实现上,通常通过日志的方式来实现。事务中的每一次操作都会记录到日志中,如果事务执行失败,可以通过日志来回滚。
3.2. 一致性 Consistency
一致性要求事务在执行前后,数据始终保持在正确的状态,既要满足业务逻辑,也需要满足数据库的约束条件。
3.3. 隔离性 Isolation
隔离性指事务在执行过程中,其他事务的执行不会影响当前事务。
在实际的生产环境中,对于数据库的读写通常是并发进行的,会存在多个事务对同一张数据表进行操作。
先考虑一个简单的情况,假设事务 A 正在更新记录 r1,事务 B 在更新记录 r2,两个事务不操作同一条记录,理论上两个事务不会有任何影响。
接下来情况稍微复杂了一些,假设事务 A 更新记录 r1,同时事务 B 在查询记录 r1,那么如果事务 A 正在执行中,事务 B 查询到的结果应该是什么样的?
为了解决多个事务同时更新或者查询同一个记录的问题,隔离性又分为了不同的隔离级别,这个在后面会详细介绍。
3.4. 持久性 Durability
持久性指事务执行完成后,也可以说事务「提交」后,对数据库会产生永久的改变,数据的状态会持久化到磁盘上。
换个角度讲,数据库的每一次更新,背后对应的就是一个个事务的提交。