Database Transactional Management

事务的特性 ACID

  • A: Atomicity(原子性): 一个事务包含多个操作,这些操作要么全部执行成功,有一个执行失败就都失败。多个操作可以看做一个操作。
  • C: Consistency(一致性) : 就是数据保持一致,对于分布式系统来说,可以理解为多个节点的数据是一致的。从一个状态转变到另外一个状态。
  • I: Isolation(隔离性): 事务并发执行时,防止多个事务交叉执行对数据一致性造成影响。
  • D: Durability(持久性): 事务提交后会被持久化到永久存储。

先说Consistency:

一致性分多种层次分别有:强一致性、弱一致性、最终一致性、单调一致性、会话一致性。

  • 强一致性: 可以理解为在任意时刻,所有节点的数据都是一样的。
  • 弱一致性: 弱一致性有多种实现,分布式系统中使用广泛实现的是「最终一致性」,不保证任一时刻每个节点的同一份数据一样。但随着时间迁移,不同节点数据总是向趋同的方向变化。DNS 服务器是个很好的「最终一致性」例子,当一个节点更新 DNS 记录后,其他节点不会立即全部更新。因为 DNS 多级缓存的存在,需要等待缓存服务器过期之后向源服务器请求更新记录才会更新。
  • 单调一致性:一个进程已经读到的值,那么后续不会再读到更早的记录。
  • 会话一致性:保证客户端和服务器交互的会话过程中,读操作可以读到更新操作之后的值。
    一致性实现的原理简析:

一致性是通过「预写日志」的方式来实现的。具体原理是:数据库在执行事务时,并不会立即执行这些操作,而是将这些操作写入「预写日志」,预写日志是保存在磁盘上的。预写日志写入完成之后数据库程序将执行预写日至中的内容,更新数据库中的数据文件。正常情况下,完成 结束事务操作之后会删除预写的日志,并告知程序执行成功。(有些数据库在删除日志前会将再次日志写进「归档日志」中,以便可以通过归档日志恢复整个库)。但在某些情况也可能发生意外,如突然断电导致数据库程序执行中断。数据库重启后,可能发生两种情况:

  1. 数据库重启后,查看「预写日志」发现一个事务,并且该事务操作最后一条记录是「结束事务」。由此可以推断,该事务可能已经执行成功但还未来得及删除日志记录,或者事务还没执行或者没执行完。但情况无论如何,数据库都将进行「前滚」操作。将「预写日志」里的操作再执行一遍。因此,事务在执行到哪一步中断的其实我们可以不用关心,事实上它也不重要。因为前滚操作会将「预写日志」中的整个内容再执行一次,以保证一致性。对于无论执行多少次都不会影响最终结果的这种特性成为「幂等性」
  2. 数据库重启后,查看「预写日志」发现一个事务,并且该事务最后一条记录不是「结束日志」,此时可以知道事务一定没有正确执行。由于没有「结束日志」记录,因此无法判断之后是否还有其他操作,因此不能执行「前滚」操作,只能执行「回滚」操作进行恢复,将以在日志中的操作反过来恢复。(数据库在写「预写日志」时,不仅记录新值同时也会记录原值)

再谈 isolation :

事务隔离性一般有四个不同的级别

  1. Read uncommited: 允许读取其他事务更改过但还未提交(事务)的数据,隔离等级最低。如事务 A 对数据 C 进行了修改(但未提交事务)。此时事务 B 读取了修改后的数据 C,而事务 A 因为某种异常进行了回滚,那么事务 B 读到的数据 C(脏数据) 就是错误的数据。
  2. Read commited: 这个级别的隔离可以避免脏读,即事务不能读取到未提交的数据。比如事务 A 修改了数据 C 但未提交事务,此时事务 B select 数据 C 不会 select 到未提交的 C ,只能 select 到修改之前的数据 C。这个级别的隔离,避免了脏读 但仍然不能 「Repeatable read」.如:事务 A select 了数据 C ,此时事务 B 对数据 C 进行修改并提交了事务。这时事务 A 还没提交,如果再次执行select 数据 C ,会惊讶的发现…两次数据不一样。即,这个级别的隔离是「unrepeatable read」 不可重复读的。
  3. Repeatable read : 可重复读取,这个级别的隔离可以保证同一个事务每次 select 的数据都是一致的。(不同的数据库引擎这个级别的隔离实现原理可能不同。一般认为通过加锁实现,如 事务A 在读取数据 C 时,不允许其他事务对数据 C 进行修改。但 InnoDB 引擎采用的 Read view 原理,第一次 select 时会生成一个 snapshot,之后的 select都从这个 snapshot 上读取,因此能保证多次 select 的结果相同,且没有加锁的操作。避免了出现死锁的情况,提高了并发的能力。) 这个级别的隔离无法避免幻读,比如在事务 A 想将表中所有人月薪不足5000的记录,都改成5000。当事务 A 执行完所有操作,但还未提交事务。此时事务 B 又插入(或删除)一条月薪不足5000的数据。然后提交事务 A B。此时事务 A 发生幻觉,好像事务没有执行成功一样。这是因为「Repeatable read」锁定的是已经读取的记录,而不是锁定整张表。
  4. Serialization: 事务串行化执行,隔离级别最高,牺牲了系统并发性。

参考文章:

数据库中隔离性的四种级别详解与例子
InnoDB 可重复读原理
数据库一致性原理浅析
什么是数据库的一致性?一致性弱意味着什么?