事务原理

事务具有四大特性, 原子性, 隔离性, 一致性, 持久性

  • 原子性: 指的是一个事务操作是不可分割的, 执行要么全部成功, 要么全部失败
  • 隔离性: 指的是, 多个事务并发操作时, 互相是隔离的, 某事务不该被其他事务所干扰
  • 一致性: 指的是事务遵循数据的完整性,唯一性约束
  • 持久性: 指的是事务如果已经提交, 那么对数据的变更就是永久的

在谈原理之前, 我想先假设出一个事务场景, 并提出一些问题, 以便更好的理解事务原理:

  • 都知道Mysql的隔离级别有四种: 读未提交, 读已提交, 可重复读, 序列化读
    • 四种隔离级别是如何实现的?
  • 原子性是不可分割的
    • 那么, 全不成功, 进行回滚, 如何实现恢复为原始数据的回滚过程呢?
    • 全部成功, 进行提交, 如何实现数据在磁盘上的真实更新的呢?
  • 持久性说, 事务已提交对数据的变更就是永久的. Mysql如何保障的, 提交总是要更新磁盘(后文用刷盘指代)的吧?
    • 假设是先刷盘后提交, 那么在刷盘的时候宕机了, 该怎么恢复处理呢?
    • 假设是先提交后刷盘, 那么在刷盘的时候宕机了, 该怎么恢复处理呢?

我们通常默认使用 InnoDB 作为存储引擎, 那么, 接下来, 从问题出发, 讨论 InnoDB事务原理

四种隔离级别是如何实现的?

在此之前, 先重新整理下, 已知的四种隔离级别

假设有事务A, B同时并发操作同一条数据, 事务A查询数据, 事务B更新数据.

  • 读未提交: 事务A会查询到事务B未提交却修改过的数据, 若是事务B回滚, 事务A读取的数据将是不正确的, 即: 脏读
  • 读已提交: 事务A仅可查询事务B提交成功后的数据, 但若是事务A进行先后两次查询(重复读), 将出现前后数据不一致的情况, 即: 不可重复读
  • 可重复读: 保证了在事务A重复读, 不受其他事务更新的影响, 前后数据一致, 但若有其他事务插入数据, 重复读将出现, 后读数据集更多的情况, 即: 幻读
  • 序列化读: 所有事务排队, 一条条的处理, 完美解决并发出现的问题

自上而下, 隔离级别越高, 事务之间的影响也越来越小, 越来越隔离, 数据越来越安全

同样的, 性能也越来越低, 当开启序列化读, 巨量事务排队的情况, 数据的安全性是拉满了, 可性能却不尽人意

Mysql的默认事务隔离级别是: 可重复读

那么, 接下来介绍, 如何实现这四种隔离级别的呢?

标准SQL事务隔离级别实现原理

解决并发事务的常见方式, 就是通过悲观锁来进行并发控制了, 标准SQL事务隔离级别的实现是依赖锁的, 我们看看它是如何实现的:

1.

多版本并发控制(MVCC)

1
2
通俗的讲,数据库中同时存在多个版本的数据,并不是整个数据库的多个版本,而是某一条记录的多个版本同时存在.
在某个事务对其进行操作的时候,需要查看这一条记录的隐藏列事务版本id,比对事务id并根据事物隔离级别去判断读取哪个版本的数据。

参考链接