0%

事务

1. 事务的 4 个基本要素

ACID 是数据库事务处理的 4 个基本要素.

  1. 原子性 Atomicity
    原子性是指数据库的事务是一个不可分割的工作单位, 只有数据库事务都成功才算成功,任何一个SQL的失败, 数据库状态都必须回退到事务开始前的状态

  2. 一致性 Consistency
    一致性是指事务将数据库的状态从一种状态转变为下一个一致的状态. 在事务的开始和结束后, 数据库的完整性约束都没有被破坏.

  3. 隔离性 Isolation
    隔离性是指事务之间对数据对象的读写是相互隔离的, 具体是提交后可见还是提交后也不可见取决于隔离等级, 前面两种情况分别为提交读(RC)和可重复读(RR).

  4. 持久性 Durability
    持久性是指事务一旦提交, 其修改是永久性的, 即使还未写入磁盘时发生宕机, 也能恢复数据.

一个支持事务的数据库, 必须具有这 4 个特性, 否则在事务过程中无法保证事务的正确性.

事务的隔离性是通过数据库锁的机制实现的, 持久性通过 Redo Log 来实现, 原子性和一致性通过 Undo Log 来实现.

Undo Log 的原理很简单, 为了满足事务的原子性, 在操作任何数据之前, 首先将数据备份到一个地方, 这个存储数据备份的地方称为 Undo Log, 然后进行数据的修改. 如果出现了错误或者用户执行了 Rollback 语句, 系统可以利用 Undo Log 中的备份将数据恢复到事务开始之前的状态.
和 Undo Log 相反, Redo Log 记录的是新数据的备份. 在事务提交前, 只要将 Redo Log 持久化即可, 不需要将数据持久化. 当系统崩溃时, 虽然数据没有持久化, 但是 Redo Log 已经持久化. 系统可以根据 Redo Log 的内容, 将所有数据恢复到最新的状态.

2. 事务的隔离级别

事务有以下 4 个隔离级别:

隔离级别 脏读 不可重复读 | 幻读
读未提交 Read Uncommitted Y Y
读已提交 Read committed N Y
可重复读 Repeatable N N
可串行化 Serializable N N

默认的事务隔离级别是 可重复读.
事务的隔离级别影响系统的并发处理能力, 级别越高, 越能保证事务的一致性, 对性能影响也越大.

之所以这样划分, 是因为并发事务会有以下 3 个问题:

  1. 脏读

即一个事务中还没有提交的数据, 被另外一个事务读到了.
如: 事务 A 开启事务从账户中取走 100 元; 但事务 A 还没提交前, 事务 B 来获取账户中余额, 发现并没有减少.

  1. 不可重复读

即在一个事务里面读取了两次某个数据, 读出来的数据不一致.
如: 事务 A 开启事务查询账户中余额为 1000 元; 同时事务 B 取走账户中 100 元, 并提交; 而事务 A 还没有结束, 又查询了一次账户余额, 发现账户中的余额为 900 元.

  1. 幻读

即在一个事务里面的操作中发现了未被操作的数据.
如: 事务 A 开启事务要更新一批数据; 同时事务 B 往数据库中插入一条记录, 并提交; 之后事务 A 提交事务时发现有一条记录没有更新到.

不可重复读和幻读的区别在于:
不可重复读是在一个事务中记录发生 变更, 需要通过行级锁解决;
幻读是在事务中表中数据发生了 新增删除, 同通过表级锁解决.

2.1. 事务隔离的实现方式

事务隔离的实现方式基本可分为 2 种:

  1. 在读取数据前, 对其加锁, 阻止其他事务对数据进行修改.

  2. 不用加任何锁, 通过一定机制生成一个数据请求时间点的一致性数据快照 (Snapshot), 并用这个快照来提供一定级别(语句级或事务级)的一致性读取. 从用户的角度来看, 好像是数据库可以提供同一数据的多个版本, 因此, 这种技术叫做数据多版本并发控制 (MultiVersion Concurrency Control, 简称MVCC), 也经常称为多版本数据库.

2.1.1. MVCC

Innodb MVCC主要是为 Repeatable-Read 事务隔离级别做的. 在此隔离级别下, A, B客户端所示的数据相互隔离, 互相更新不可见.

了解 Innodb 的行结构, Read-View 的结构对于理解 Innodb MVCC 的实现由重要意义.

Innodb 存储的最基本 row 中包含一些额外的存储信息 DATA_TRX_ID, DATA_ROLL_PTR, DB_ROW_ID, DELETE_BIT.
6 个字节的 DATA_TRX_ID 标记了最新更新这条行记录的事务 ID, 每处理一个事务, 其值自动 +1.
7 个字节的 DATA_ROLL_PTR 指向当前记录项的 rollback segment 的 undo log 记录, 找之前版本的数据就是通过这个指针.
6 个字节的 DB_ROW_ID, 当由 Innodb 自动产生聚集索引时, 聚集索引包括这个 DB_ROW_ID 的值, 否则聚集索引中不包括这个值.
DELETE BIT 位用于标识该记录是否被删除, 这里的不是真正的删除数据, 而是标志出来的删除.真正意义的删除是在commit的时候

3. 更新丢失问题

当两个或多个事务选择同一行, 然后基于最初选定的值更新该行时, 由于每个事务都不知道其他事务的存在, 就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新.
对于这个问题, 需要开发人员在业务层控制, 规避这个问题的发生, 如使用全局锁等, 控制数据, 在同一时间只有一个人能访问同一数据资源.

https://blog.csdn.net/zx64881926/article/details/75150421