第七章 事务 阅读总结

第七章 事务 阅读总结_第1张图片

        事务(Transaction)是数据库区别于文件系统的重要特性之一。 在文件系统中, 如果正在写文件, 但是操作系统突然崩溃了, 这个文件就很有可能被破坏。 当然, 有一些机制可以把文件恢复到某个时间点。 不过, 如果需要保证两个文件同步, 这些文件系统可能就显得无能为力了。 例如, 在需要更新两个文件时, 更新完一个文件后, 在更新完第二个文件之前系统重启了, 就会有两个不同步的文件。

        这正是数据库系统引入事务的主要目的 :事务会把数据库从一种一致状态转换为另 一种一致状态。 在数据库提交工作时, 可以确保要么所有修改都已经保存了, 要么所有修改都不保存。

InnoDB存储引擎中的事务完全符合ACID的特性。 ACID是以下4个词的缩写:

原子性(atomicity)

一致性(consistency)

隔离性(isolation)

持久性(durability)

7.1 认识事务

7.1.1 概述

        事务可由一条非常简单的SQL语句组成, 也可以由一组复杂的SQL语句组成。事务是访问并更新数据库中各种数据项的一个程序执行单元。 在事务中的操作, 要么都做修改, 要么都不做, 这就是事务的目的, 也是事务模型区别与文件系统的重要特征之一。

        理论上说,事务有着极其严格的定义,它必须同时满足四个特性,即通常所说的事务的ACID特性。值得注意的是,虽然理论上定义了严格的事务要求,但是数据库厂商出于各种目的,并没有严格去满足事务的ACID标准。

        原子性指整个数据库事务是不可分割的工作单位。只有使事务中所有的数据库操作都执行成功,才算整个事务成功。事务中任何一个SQL语句执行失败,已经执行成功的SQL语句也必须撤销,数据库状态应该退回到执行事务前的状态。

        一致性指事务将数据库从一种状态转变为下一种一致的状态。在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。

        隔离性还有其他的称呼,如并发控制(concurrency control)、可串行化(serializability)、锁(locking)等。事务的隔离性要求每个读写事务的对象对其他事务的操作对象能相互分离,即该事务提交前对其他事务都不可见,通常这使用锁住一个实体对象的子集,以此来提高事务之间并发度。

       持久性, 事务一旦提交,其结果就是永久性的。即使发生宕机等故障,数据库也能将数据恢复。需要注意的是,只能从事务本身的角度来保证结果的永久性。

7.1.2  分类

从事务理论的角度来说,可以把事务分为以下几种类型:

1.扁平事务(Flat Transactions)

2.带有保存点的扁平事务(Flat Transactions with Savepoints)

3.链事务(Chained Transactions)

4.嵌套事务(Nested Transactions)

5.分布式事务(Distributed Transactions)

        扁平事务(Flat Transaction)是事务类型中最简单的一种, 但在实际生产环境中,这可能是使用最为频繁的事务。 在扁平事务中, 所有操作都处于同一层次, 其由BEGIN WORK开始, 由COMMIT WORK或ROLLBACKWORK结束, 其间的操作是原子的,要么都执行, 要么都回滚。 因此扁平事务是应用程序成为原子操作的基本组成模块。

        带有保存点的扁平事务 (Flat Transactions with Savepoint), 除了支持扁平事务支持的操作外, 允许在事务执行过程中回滚到同一事务中较早的一个状态。 这是因为某些事务可能在执行过程中出现的错误并不会导致所有的操作都无效, 放弃整个事务不合乎要求, 开销也太大。 保存点 (Savepoint) 用来通知系统应该记住事务当前的状态, 以便当之后发生错误时, 事务能回到保存点当时的状态。

        对于扁平的事务来说, 其隐式地设置了一个保存点。 然而在整个事务中, 只有这一 个保存点, 因此, 回滚只能回滚到事务开始时的状态。 保存点用SAVEWORK函数来建立, 通知系统记录当前的处理状态。 当出现问题时, 保存点能用作内部的重启动点, 根据应用逻辑, 决定是回到最近一个保存点还是其他更早的保存点。

        链事务(Chained Transaction)可视为保存点模式的一种变种。 带有保存点的扁平事务, 当发生系统崩溃时, 所有的保存点都将消失, 因为其保存点是易失的(volatile),而非持久的(persistent)。 这意味着当进行恢复时, 事务需要从开始处重新执行, 而不能从最近的一个保存点继续执行。

        链事务的思想是: 在提交一个事务时, 释放不需要的数据对象, 将必要的处理上下文隐式地传给下一个要开始的事务。注意, 提交事务操作和开始下一个事务操作将合并为一个原子操作。这意味着下一个事务将看到上一个事务的结果, 就好像在一个事务中进行的一样。

第七章 事务 阅读总结_第2张图片

        链事务与带有保存点的扁平事务不同的是,带有保存点的扁平事务能回滚到任意正确的保存点。而链事务中的回滚仅限于当前事务,即只能恢复到最近一个的保存点。对于锁的处理,两者也不相同。链事务在执行COMMIT后即释放了当前事务所持有的锁, 而带有保存点的扁平事务不影响迄今为止所持有的锁。

        嵌套事务(NestedTransaction)是一个层次结构框架。由一个顶层事务(top ­level transaction)控制着各个层次的事务。顶层事务之下嵌套的事务被称为子事务(subtransaction), 其控制每一个局部的变换。

第七章 事务 阅读总结_第3张图片

        分布式事务 (Distributed Transactions) 通常是一个在分布式环境下运行的扁平事 务, 因此需要根据数据所在位置访问网络中的不同节点。

        对于 lnnoDB 存储引擎来说, 其支持扁平事务、 带有保存点的事务、 链事务、 分布式事务。对于嵌套事务,其并不原生支持,因此,对有并行事务需求的事务来说。MySQL数据库或InnoDB存储引擎就显得无能为力了。然而用户仍可以通过带有保存点的事务来校拟串行的嵌套事务。

7.2 事务的实现

        原子性、一致性、持久性通过数据库的redo log和undolog来完成。redolog称为重做日志,用来保证事务的原子性和持久性。undo log用来保证事务的一致性。

        有的 OBA 或许会认为 undo 是 redo 的逆过程,其实不然。 redo 和 undo 的作用都可以视为是一种恢复操作,redo 恢复提交事务修改的页操作,而 undo 回滚行记录到某个特定版本。因此两者记录的内容不同,redo 通常是物理日志,记录的是页的物理修改操 作。undo 是逻辑日志,根据每行记录进行记录。

7.2.1 redo

1.基本概念

        重做日志用来实现事务的持久性,即事务ACID中的D。其由两部分组成:一是内存中的重做日志缓冲(redolog buffer), 其是易失的;二是重做日志文件(redolog file),其是持久的。

        InnoDB 是事务的存储引擎,其通过 Force Log at Commit 机制实现事务的持久性,即当事务提交 (COMMIT) 时,必须先将该事务的所有日志写入到重做日志文件 进行持久化,待事务的 COMMIT 操作完成才算完成。这里的日志是指重做日志,在 InnoDB 存储引擎中,由两部分组成,即 redo log 和 undo log。redo log 用来保证事务的持久性,undo log 用来帮助事务回滚及 MVCC 的功能。redo log 基本上都是顺序写的, 在数据库运行时不需要对 redo log 的文件进行读取操作。而 undo log 是需要进行随机读 写的。

        为了确保每次日志都写入重做日志文件,在每次将重做日志缓冲写人重做日志文件后,InnoDB存储引擎都需要调用一次 fsync 操作。由于重做日志文件打开并没有使用 O_DIRECT 选项,因此重做日志缓冲先写入文件系统缓存。为了确保重做日志写入磁盘,必须进行一次fsync 操作。由于fsync 的效率取决于磁盘的性能, 因此磁盘的性能绝定了事务提交的性能,也就是数据库的性能。

        lnnoDB 存储引擎允许用户手工设置非持久性的情况发生,以此提高数据库的性能。即当事务提交时,日志不写入重做日志文件, 而是等待一个时间周期后再执行fsync 操作。由于并非强制在事务提交时进行一次fsync 操作, 显然这可以显著提高数据库的性能。但是当数据库发生宅机时, 由于部分日志未刷新到磁盘, 因此会丢失最后一段时间的事务。

        在MySQL数据库中还有一种二进制日志(binlog)其用来进行POINT-IN-TIME(PIT)的恢复及主从复制(Replication)环境的建立。从表面上看其和重做日志非常相似, 都是记录了对于数据库操作的日志。 然而, 从本质上来看, 两者有着非常大的不同。

        首先, 重做日志是在InnoDB存储引擎层产生, 而二进制日志是在MySQL数据库 的上层产生的, 并且二进制日志不仅仅针对千InnoDB存储引擎, MySQL数据库中的任何存储引擎对于数据库的更改都会产生二进制日志。

        其次, 两种日志记录的内容形式不同。 MySQL数据库上层的二进制日志是一种逻辑日志, 其记录的是对应的SQL语句。而InnoDB存储引擎层面的重做日志是物理格式 日志, 其记录的是对于每个页的修改。

        此外, 两种日志记录写入磁盘的时间点不同, 如图7-6所示。 二进制日志只在事务提交完成后进行一次写入。 而InnoDB存储引擎的重做日志在事务进行中不断地被写入,这表现为日志并不是随事务提交的顺序进行写入的。


第七章 事务 阅读总结_第4张图片

        从图7-6中可以看到, 二进制日志仅在事务提交时记录, 并且对于每一个事务, 仅包含对应事务的一个日志。 而对于lnnoDB存储引擎的重做日志, 由于其记录的是物理操作日志, 因此每个事务对应多个日志条目, 并且事务的重做日志写入是并发的, 并非 在事务提交时写入, 故其在文件中记录的顺序并非是事务开始的顺序。 *Tl、 *T2、 *T3表示的是事务提交时的日志。

2. log block

        在InnoDB存储引擎中, 重做日志都是以512字节进行存储的。 这意味着重做日志缓存、 重做日志文件都是以块(block)的方式进行保存的, 称之为重做日志块(redo log block), 每块的大小为512字节。

        若一个页中产生的重做日志数橄大于512字节, 那么需要分割为多个重做日志块进行存储。 此外, 由于重做日志块的大小和磁盘扇区大小一样, 都是512字节, 因此重做日志的写入可以保证原子性,不需要doublewrite技术。

        重做日志块除了日志本身之外,还由日志块头(logblock header)及日志块尾(log tailer)两部分组成,重做日志头一共占用 12 字节, 重做日志尾占用 8 字节。 故每 个重做日志块实际可以存储的大小为 492 字节 (512-12-8)。图7-7 显示了重做日志块缓存的结构。


第七章 事务 阅读总结_第5张图片

3.log group

        log group为重做日志组,其中有多个重做日志文件。虽然源码中已支持loggroup 的镜像功能,但是在ha_innobase.cc文件中禁止了该功能。因此InnoDB存储引擎实际只有一个loggroup。

        log group是一个逻辑上的概念,并没有一个实际存储的物理文件来表示loggroup 信息。loggroup由多个重做日志文件组成,每个loggroup中的日志文件大小是相同的,且在InnoDB1.2版本之前,重做日志文件的总大小要小于4GB(不能等于4GB)。 从InnoDB1.2版本开始重做日志文件总大小的限制提高为了512GB。InnoSQL版本的 InnoDB存储引擎在1.1版本就支持大于4GB的重做日志。

        重做日志文件中存储的就是之前在logbuffer中保存的logbloc, 因此其也是根据块的方式进行物理存储的管理,每个块的大小与logblock一样,同样为512字节。在 InnoDB存储引擎运行过程中,logbuffer根据一定的规则将内存中的logblock刷新到磁盘。这个规则具体是:

事务提交时

当logbuffer中有一半的内存空间已经被使用时

log checkpoint时

        对于logblock的写人追加(append)在redolog file的最后部分,当一个redologfile被写满时,会接着写入下一个redolog file, 其使用方式为round-robin。

        虽然logblock总是在redolog file的最后部分进行写入,有的读者可能以为对redo log file的写人都是顺序的。其实不然,因为redolog file除了保存logbuffer刷新到磁盘的logblock, 还保存了一些其他的信息,这些信息一共占用2KB大小,即每个redolog file的前2KB的部分不保存logblock的信息。对于loggroup中的第一个redolog file, 其前2KB的部分保存4个512字节大小的块,其中存放的内容如表7-4所示。

第七章 事务 阅读总结_第6张图片

4. 重做日志格式

        不同的数据库操作会有对应的重做日志格式。此外,由于 InnoDB 存储引擎的存储管理是基于页的,故其重做日志格式也是基于页的。虽然有着不同的重做日志格式,但是它们有着通用的头部格式,如图 7-10 所示。

通用的头部格式由以下3部分组成:

redo_log_type: 重做日志的类型。

space: 表空间的ID。

page_ no: 页的偏移拭。

7.2.2 undo

1.基本概念

        重做日志记录了事务的行为,可以很好地通过其对页进行“重做”操作。但是事务 有时还需要进行回滚操作,这时就需要undo。因此在对数据库进行修改时,InnoDB存储引擎不但会产生redo,还会产生一定世的undo。这样如果用户执行的事务或语句由于某种原因失败了,又或者用户用一条ROLLBACK语句请求回滚,就可以利用这些undo 信息将数据回滚到修改之前的样子。 

        redo存放在重做日志文件中,与redo不同,undo存放在数据库内部的一个特殊段(segment)中,这个段称为undo段(undosegment)。undo段位于共享表空间内。可以通过py_innodb_page_info.py工具来查看当前共享表空间中undo的数蜇。如下代码显示 当前的共享表空间ibdatal内有2222个undo页。

7.2.3 purge

        delete 和 update 操作可能并不直接删除原有的数据。       

        purge 用于最终完成 delete 和 update 操作。 这样设计是因为 InnoDB 存储引擎支持MVCC, 所以记录不能在事务提交时立即进行处理。 这时其他事物可能正在引用这行,故 InnoDB 存储引擎需要保存记录之前的版本。 而是否可以删除该条记录通过 purge 来进行判断。 若该行记录已不被任何其他事务引用, 那么就可以进行真正的 delete 操作。可见, purge 操作是清理之前的 delete 和 update 操作, 将上述操作“最终”完成。而实际操作Delete操作,清理之前行记录的版本。

7.2.4 group commit

        若事务为非只读事务,则每 次 事务提交时需要进行一次fsync操作,以此保证 重做日志都已经写入磁盘。当数据库发生右机时,可以通过重做日志进行恢复。虽然固态硬盘的出现提高了磁盘的性能,然而磁盘的fsync性能是有限的。为了提高磁盘fsync的效率,当前数据库都提供了 group commit的功能,即一次fsync 可以刷新确保多个事务日志被写人文件。对于InnoDB存储引擎来说,事务提交时会进行两个阶段的操作:

1) 修改内存中事务对应的信息,并且将日志写入 重做日志缓冲。

2)调用fsync 将确保日志都 从重做日志缓冲写入磁盘。

        步骤2) 相对步骤I) 是一个较慢的 过程,这是因为存储引擎需要与磁盘打交道。但当有事务进行 这个过程时,其他事务 可以进行步骤I)的操作,正在提交的事物完成提交操作后,再次进行步骤2)时,可以将多个事务的 重做日志通过 次fsync刷新到磁盘,这样就大大地减少了磁盘的压力,从而提高了数据库的整体性能。对于写入或更新较为频繁的操作,group commit的效果尤为明显。

        然而在InnoDBI.2版本之前,在开启二进制日志后,InnoDB存储引擎的 group commit功能会失效,从而导致性能的下降。并且在线环境多使用 replication环境,因此 二进制日志的选项基本都为开启状态,因此这个问题尤为显著。

        导致这个问题的原因是在开启二进制日志后,为了保证存储引擎层中的事务和二进制日志的一致性,二者之间 使用了两阶段事务,其步骤如下:

1)当事务提交时InnoDB存储引擎进行 prepare操作。

2) MySQL数据库上层写入二进制日志。

3) InnoDB存储引擎层将日志写入重做日志文件。

a) 修改内存中事务对应的信息, 并且将日志写入 重做日志缓冲。

b) 调用fsync将确保日志 都从重做日志缓冲写入磁盘。

        一旦步骤2) 中的操作完成, 就确保了事务的提交, 即使在执行步骤3) 时数据库发生了宅机。 此外需要注意的是, 每个步骤都需要进行一次fsync操作才能保证上下两层数据的一致性。 步骤2)的fsync由参数sync_ bin log控制, 步骤3)的fsync由参数nnodb _flush_log_ at_trx _ commit控制。因此上述整个过程如图7-18所示。


第七章 事务 阅读总结_第7张图片

7.3 事务控制语句

        在MySQL命令行的默认设置下, 事务都是自动提交(auto commit)的, 即执行SQL语句后就会马上执行COMMIT操作。 因此 要显式地开启一个事务需使用命令 BEGIN、START TRANSACTION, 或者执行命令SET AUTOCOMMIT=O, 禁用当前会 话的自动提交。 每个数据库厂商自动提交的设置都不相同, 每个OBA或开发人员需要非常明白这一点, 这对之后的 SQL编程会有非凡的意义, 因此用户不能以之前的经验来判断MySQL 数据库的运行方式。 在具体介绍其含义之前, 先来看看用户可以使用哪些 事务控制语句。

START TRANSACTION I BEGIN: 显式地开启一个事务。

COMMIT: 要想使用这个语句 的最简形式, 只需发出COMMIT。 也可以更详细一些, 写为COMMIT WORK, 不过这二者几乎是等价的。COMMIT会提交事务,并使得巳对数据库做的所有修改成为永久性的。

ROLLBACK: 要想使用这个语句 的最简形式, 只需发出ROLLBACK。 同样地,也可以写为ROLLBACK WORK, 但是二者几乎是等价的。 回滚会结束用户的事 务, 并撤销正在进行的所有未提交的修改。

SAVEPOJNT identifier : SAVEPOINT允许在事务中创建一个保存点, 一个事务中可以有多个SAVEPOINT。

RELEASE SAVEPOINT identifier: 删除一个事务的 保存点, 当没有一个保存点执行这句语句 时,会抛出一个异常。

ROLLBACK TO[SAVEPOINT]identifier: 这个语句与SAVEPOINT命令一起使用。可以把事务回滚到标记点, 而不回滚在此 标记点之前的任何工作。 例如可以发出 两条UPDATE 语句 , 后面跟一个SAVEPOINT, 然后又是两条DELETE 语句。 如果执行DELETE语句期间出现了某种异常情况, 并且捕获到这个异常, 同时发出 了ROLLBACK TO SAVEPOINT命令, 事务就 会回滚到指定的 SAVEPOINT, 撤销DELETE 完成的所有工作 , 而UPDATE语句完成的工作不受影响。

        SET TRANSACTION : 这个语句用来设置事务的隔离级别。InnoDB存储引擎提供的事务隔离级别有: READ UNCOMMITTED、READ COMMITTED、 REPEATABLE READ、SERIALIZABLE。

        START TRANSACTION、BEGIN语句都可以在MySQL命令行下显式地开启一个事务。但是在存储过程中,MySQL数据库的分析器会自动将BEGIN识别为BEGIN…END, 因此在存储过程中只能使用 START TRANSACTION语句来开启一个事务。

        COMMIT和COMMIT WORK语句基本是一致的,都是用来提交事务。不同之处在于COMMIT WORK用来控制事务结束后的行为是CHAIN还是RELEASE的。如果是CHAIN方式,那么事务就变成了链事务。

        用户可以通过参数completion_type来进行控制,该参数默认为0, 表示没有任何操作。在这种设置下COMMIT和COMMIT WORK是完全等价的。当参数completion_ type的值为1时,COMMIT WORK等同于COMMIT AND CHAIN, 表示马上自动开启一个相同隔离级别的事务。

7.5 对于事务操作的统计

        由于InnoDB存储引擎是支持事务的, 因此lnnoDB存储引擎的应用需要在考虑每秒请求数(Question Per Second, QPS)的同时, 应该关注每秒事务处理的能力(Transaction Per Second, TPS)。

        计算TPS的方法是(com_commit+com_rollback) /time。 但是利用这种方法进行计算的前提是:所有的事务必须都是显式提交的, 如果存在隐式地提交和回滚(默认autocommit= 1) , 不会计算到com_commit和com_rollback变量中。

7.6 事务的隔离级别

SQL标准定义的四个隔离级别为:

READ UNCOMMITTED

READ COMMITTED

REPEATABLE READ

SERIALIZABLE

        READ UNCOMMITTED称为浏览访问(browse access), 仅仅针对事务而言的READ COMMITTED称为游标稳定(cursor stability)。SQL和SQL2标准的默认事务隔离级别是SERIALIZABLE。

        InnoDB存储引擎默认支持的隔离级别是REPEATABLE READ, 但是与标准SQL不同的是,InnoDB存储引擎在REPEATABLE READ 事务隔离级别下,使用Next-Key-Lock锁的算法,因此避免幻读的产生。这与其他数据库系统(如 Micro soft SQL Server 数据库)是不同的 。所以说,lnnoDB存储引擎在默认的 REPEATABLE READ的事务隔离级别下已经能完全保证事务的隔离性要求 ,即达到 SQL标准的 SERIALIZABLE隔离级别。

        隔离级别越低,事务请求的锁越少或保持锁的时间就越短。这也是为什么大多数数据库系统默认的事务隔离级别是READ COMMITTED。

7.7 分布式事务

7.7.1 MySQL数据库分布式事务

        InnoDB 存储引擎提供了对 XA 事务的支持,并通过 XA事务来支持分布式事务的实现。分布式事务指的是允许多个独立的事务资源 (transactional resources) 参与到一个全局的事务中。事务资源通常是关系型数据库系统,但也可以是其他类型的资源。全局事务要求在其中的所有参与的事务要么都提交,要么都回滚,这对于事务原有的ACID 要求又有了提高。另外,在使用分布式事务时,InnoDB 存储引擎的事务隔离级别必须设置为SERIALIZABLE。

        XA事务允许不同数据库之间的分布式事务,如一台服务器是 MySQL 数据库的,另一台是 Oracle 数据库的,又可能还有一台服务器是 SQL Server 数据库的,只要参与在全局事务中的每个节点都支持XA事务。

        XA事务由一个或多个资源管理器(Resource Managers)、一个事务管理器 (Transaction Manager)以及一个应用程序(Application Program)组成。

资源管理器:提供访问事务资源的方法。通常一个数据库就是一个资源管理器。 

事务管理器:协调参与全局事务中的各个事务。需要和参与全局事务的所有资源管理器进行通信。

应用程序:定义事务的边界,指定全局事务中的操作。

        在MySQL数据库的分布式事务中,资源管理器就是MySQL数据库,事务管理器为连接MySQL服务器的客户端。图7-22显示了一个分布式事务的模型。

第七章 事务 阅读总结_第8张图片

        分布式事务使用两段式提交(two-phase commit)的方式。在第一阶段,所有参与 全局事务的节点都开始准备(PREPARE), 告诉事务管理器它们准备好提交了。在第二阶段,事务管理器告诉资源管理器执行ROLLBACK还是COMMIT。如果任何一个节点显示 不能提交,则所有的节点都被告知需要回滚。可见与本地事务不同的是,分布式事务需要多一次的 PREPARE 操作,待收到所有节点的同意信息后,再进行COMMIT或是ROLLBACK操作。

7.7.2 内部XA事务

        之前讨论的分布式事务是外部事务,即资源管理器是MySQL数据库本身。在MySQL数据库中还存在另外一种分布式事务,其在存储引擎与插件之间,又或者在存储引擎与存储引擎之间,称之为内部XA事务。

        最为常见的内部 XA事务存在于 binlog 与 lnnoDB 存储引擎之间。由于复制的需要,因此目前绝大多数的数据库都开启了 binlog 功能。在事务提交时,先写二进制日志,再写 InnoDB 存储引擎的重做日志。对上述两个操作的要求也是原子的,即二进制日志和重做日志必须同时写入。若二进制日志先写了,而在写入 InnoDB 存储引擎时发生了者机,那么 slave 可能会接收到 master 传过去的二进制日志并执行,最终导致了主从不一致的情况。如图7-23所示。

        在图 7-23 中,如果执行完心、@后 在步骤@之前 MySQL 数据库发生了宕机 ,则会发生主从不一致的情况。为 了解决这个问题,MySQL 数据库在 binlog 与 InnoDB 存储引擎之间采用XA事务。当事务提交时,InnoDB 存储引擎会先做一个PREPARE操作,将事务的xid写入,接着进行二进制日志的写入,如图 7-24 所示。如果在 InnoDB 存储引擎提交前,MySQL 数据库宥机了,那么 MySQL 数据库在重启后会先检查准备的 UXID 事务是否已经提交,若没有,则在存储引擎层再进行一次提交操作。

第七章 事务 阅读总结_第9张图片

7.9 长事务

        长事务 (Long-Lived Transactions), 顾名思义, 就是执行时间较长的事务。比如, 对于银行系统的数据库, 每过一个阶段可能需要更新对应账户的利息。 如果对应账号的数量非常大, 例如对有 1 亿用户的表 account, 需要执行下列语句:

        这时这个事务可能需要非常长的时间来完成。 可能需要1个小时, 也可能需要4、 5个小时, 这取决于数据库的硬件配置。 DBA和开发人员本身能做的事情非常少。 然而, 由 于事务 ACID 的特性, 这个操作被封装在一个事务中完成。 这就产生了一个问题, 在执行 过程中, 当数据库或操作系统、 硬件等发生问题时, 重新开始事务的代价变得不可接受。 数据库需要回滚所有巳经发生的变化, 而这个过程可能比产生这些变化的时间还要长。 因此, 对于长事务的问题, 有时可以通过转化为小批量 (mini batch) 的事务来进行处理。 当事务发生错误时,只需要回滚一部分数据,然后接着上次已完成的事务继续进行。


你可能感兴趣的:(第七章 事务 阅读总结)