1. 数据库事务知识

1.1 数据库事务的 4 个基本特征: ACID
  1. 原子性(Atomic): 一个事务是不可分割的整体, 其内的操作要么全部成功, 要么全部失败.
  2. 一致性(Consistency): 事务确保数据库从一个一致状态转变到另一个一致的状态. 一致状态指的是数据库应满足完整性约束. 比如 A+B 有 1000 元, 在 A 转帐到 B 300 后, 事务完成时, A + B 仍是 1000 元, 这保持了一致性
  3. 隔离性(Isolation): 在多并发执行事务时, 事务与事务之间是隔离开执行的.
  4. 持久性(Durability): 已被提交的了事务对数据库的修改被永久保存在数据库中.
1.2 数据库并发产生的问题

2 种更新丢失(第一类更新丢失, 第二类更新丢失), 3 种读错误(脏读, 不可重复读, 幻读)

  • 第一类更新丢失: 即 回滚事务 导致的更新丢失, 事务 A, B 分别读取到状态, 事务 B 修改了状态并提交, 但事务 A 回滚了事务, 把 B 的提交给覆盖了
时间点事务 A事务 B
T1事务开始
T2事务开始
T3查询帐户余额为 1000
T4查询帐户余额为 1000
T5存入 100
T6提交事务, 总额变为 1100
T7取出 100, 总额变为 900
T8回滚事务, 总额变为 1000(事务 B 的提交更新丢失了)
  • 第二类更新丢失: 即 提交事务 导致了更新丢失. 事务 A, B 分别读取状态, A, B 都修改了状态, 然后 B 先提交了事务, A 再提交事务, A 的提交把 B 的状态给覆盖了
时间点事务 A事务 B
T1事务开始
T2事务开始
T3查询帐户余额为 1000
T4查询帐户余额为 1000
T5取出 100, 余额变为 900
T6提交事务
T7取出 100, 余额变为 900
T8提交事务(已经取出了 200, 但余额还是900,事务 A 的提交覆盖了 B 的提交)
  • 脏读: 事务 A 读到了事务 B 未提交的数据
时间点事务 A事务 B
T1事务开始
T2事务开始
T3查询帐户余额为 1000
T4查询帐户余额为 1000
T5取出 100, 余额变为 900
T6查询帐户余额为 900(读到了 B 还没提交的数据)
T7撤消事务, 余额变为 1000
T8存入 100, 余额变为 1000
T9提交事务(B 已经回滚了事务, 但存入 100 后余额还是 1000)
  • 不可重复读: 事务 A 在别的事务 B 提交前和提交后的两次读取到的数据不一致
时间点事务 A事务 B
T1事务开始
T2事务开始
T3查询帐户余额为 1000
T4查询帐户余额为 1000
T5取出 100, 余额变为 900
T6提交事务
T7查询余额变为 900(同一个事务中, 两次读取得到的数据不一致)
  • 幻读: 事务 A 讲到了事务 B 已提交的新插入的数据, 与不可重复读的区别是, 不可重复读读到的是更新的老数据, 幻读读到的新插入的数据
时间点事务 A事务 B
T1事务开始
T2事务开始
T3查询 Z 所有的帐户总余额为 1000
T4为 Z 添加新帐户, 并存入 100
T5提交事务
T6再次查询 Z 所有的帐户总额变为 1100(同一个事务中, 两次读取得到的数据不一致)
1.3 事务的隔离级别

事务的并发导入了上面的 5 个问题, 两类更新丢失, 三种读问题, 根所业务的不同需要, 使用不同级别的事务隔离

  • 读未提交的数据 READ UNCOMMITED: 事务 A 可以读取别的事务 B 还未提交数据
  • 读已提交的数据 READ COMMITED: 该事务 A 可以读取别的是事务 B 已提交的数据
  • 可重复读 REPEATABLE READ: 事务 A 可以读到别的事务 B 提交的新插入的数据, 但不能读到对已经的记录更新后的数据
  • 串行化 SERIALIZABLE: 事务隔离的最高级别, 一个事务完全看到不别的是事务的提交, 只有一个事务完成时, 别的事务才能开始, 严格的队列顺序执行

✘ 指在这个隔离级别时可避免这个问题, ✔︎ 指在该隔离级别时会产生该问题

隔离级别第一类更新丢失第二类更新丢失脏读不可重复读幻读
读未提交的数据 READ UNCOMMITED✔︎✔︎✔︎✔︎
读已提交的数据 READ COMMITED✔︎✔︎✔︎
可重复读 REPEATABLE READ✔︎
串行化 SERIALIZABLE