事务 事务会把数据库从一种一致状态转换为另一种一致状态。在数据库提交工作时,可以确保要么所有修改都已经保存,要么所有修改都不保存。
特性 InnoDB存储引擎中的事务完全符合ACID的特性(A:Atomic,C:Consistency,I:Isolation,D:Durability)。
原子性 数据库事务是不可分割的工作单位。只有使事务中所有的数据库操作都执行成功,才算整个事务成功。事务中任何一个SQL执行失败,已经执行成功的SQL也必须撤销,数据库状态应该退回到执行事务前的状态。
一致性 事务将数据库从一种状态变更为另一种一致的状态。在事务开始前和事务结束后,数据库的完整性约束没有被破坏。事务是一致性的单位,如果事务中某个动作失败了,系统可以自动撤销事务,返回初始化的状态。
隔离性 每个读写事务的对象对其他事务的操作对象能相互分离,该事务提交前对其他事务都不可见,通常使用锁来实现。
数据库系统中都提供了一种粒度锁的策略,允许事务仅锁住一个实体对象的子集,来提高事务之间的并发性。
持久性 事务一旦提交,其结果就是永久性的。即使当数据库崩溃需要恢复时,也能保证恢复后提交的数据都不会丢失
分类 扁平事务 事务类型中最简单,生产环境中使用最为频繁的一种事务类型。 在扁平事务中,所有操作都处于同一层次,其由Begin Work开始,有Commit Work或者Rollback work结束,其间操作是原子的,要么都执行,要么都回滚。 扁平事务是应用程序成为原子操作的基本组成模块。
缺点: 不能提交或者回滚事务的某一部分,或者分几个步骤提交。
带有保存点的扁平事务 除了支持扁平事务支持的操作外,允许在事务执行过程中回滚到同一事务中较早的一个状态。
这是因为某些事务可能在执行过程中出现的错误并不会导致所有的操作都无效,放弃整个事务不合要求,开销也太大。保存点用来通知系统应该记住事务的当前状态,以便当之后发生错误时,事务能回到保存点当时的状态。
缺点: 当系统发生崩溃时,所有的保存点都将消失。因为其保存点事易失的,而非持久的。 这意味着当进行恢复时,事务需要从开始处重新执行,而不能从最近的一个保存点继续执行。
链事务 保存点模式的一个变种。在提交一个事务时,释放不需要的数据对象,将必要的处理上下文隐式地传给下一个要开始的事务。其中,提交事务操作和开始下一个事务操作将合并为一个原子操作。下一个事务将看到上一个事务的结果,就好像在一个事务中进行的一样。
链式事务与带有保存点的扁平事务不同的是,带有保存点的扁平事务能回滚到任意正确的保存点。 链式事务中的回滚仅限于当前事务,即智能恢复到最近一个的保存点。 对于锁的处理,两者也不相同。 链式事务在执行commit后就释放了当前事务所持有的锁,而带有保存点的扁平事务不影响迄今为止所持有的锁。
嵌套事务 一个层次结构框架,由一个顶层事务控制着各个层次的事务。顶层事务之下嵌套的事务被称为子事务,其控制每一个局部的变换。
1)嵌套事务是由若干事务组成的一棵树,子树既可以是嵌套事务,也可以是扁平事务 2)处在叶子结点的事务是扁平事务。但是每个子事务从根到叶子结点的距离是可以不同的。 3)位于根结点的事务称为顶层事务,其他事务称为子事务。事务的前驱称为父事务,事务的下一层称为子事务。 4)子事务既可以提交也可以回滚,但是提交操作并不马上生效,除非其父事务应提交。任何子事务都在顶层事务提交后才真正的提交。 5) 树中任意一个事务的回滚回引起它所有子事务一同回滚,子事务仅保留ACI的特性,不具有D的特性。
在Moss理论中,所有的工作都是由叶子结点来完成的,只有叶子结点的事务才能访问数据库、发送消息、获取其他类型的资源。而高层的事务仅负责逻辑控制,解决何时调用相关的子事务。
即使一个系统不支持嵌套事务,用户也可以通过保存点技术来模拟嵌套事务。
分布式事务 在分布式环境下运行的扁平事务,因此需要根据数据所在位置访问网络中的不同结点。
InnoDB存储引擎支持扁平事务、带有保存结点的扁平事务、链事务、分布式事务。并不原生支持嵌套事务。
实现 事务的隔离性由锁来实现。 原子性、一致性、持久性通过数据库的redo log和undo log来完成。 redolog 用来保证事务的原子性和持久性。 undolog 用来保证事务的一致性。
redo Redo 用来实现事务的持久性,是InnoDB存储引擎用来记录对于每个页的修改,它在事务的进行中不断的被写入。 由于是物理操作日志,每个事务对应多个日志条目。并且事务的重做日志是并发写入的,因此在文件中记录的顺序并不是事务的顺序。
其由两部分组成: 1)易失的内存中的重做日志缓冲 redo log buffer 2)持久的重做日志文件 redo log file
InnoDB存储引擎通过Force Log At Commit机制实现事务的持久性,事务提交时必须先将该事务的所有日志写入到重做日志文件进行持久化,待事务的commit操作完成才完成。 redo log都是顺序写的,在数据库运行时不需要对redo log的文件进行读取操作。
为了确保每次日志都写入redo log file,在每次重做日志缓冲写入重做日志文件后,InnoDB存储引擎都需要调用一次fsync操作,由于重做日志文件打开并没有使用O_DIRECT选项,因此重做日志缓冲先写入文件系统缓存。为了确保重做日志写入磁盘,必须进行一次fsync操作。由于fsync的效率取决于磁盘的性能,因此磁盘的性能决定了事务提交(数据库)的性能。
InnoDB存储引擎允许用户手工设置非持久的情况发生来提高数据库的性能。当事务提交时,日志不写入重做文件,等待一个时间周期后再执行fsync操作。但是当数据库发生宕机时,由于部分日志未刷新到磁盘,因此回丢失最后一段时间的事务。
innodb_flush_log_at_trx_commit用来控制重做日志刷新到磁盘的策略。 默认值为1,表示事务提交时必须调用一次fsync操作。 值为0:表示事务提交时不进行写入重做日志操作,这个操作仅在master thread中完成,master thread每秒都会进行一次重做日志文件的fsync操作。 值为2:表示事务提交时将重做日志写入重做日志文件,但仅写入文件系统的缓存中,不进行fsync操作。 当Mysql宕机时并不会发生丢失,但是操作系统宕机时,重起数据库后回丢失未从文件系统缓存刷新到重做日志文件的那部分事务。
日志块 在InnoDB存储引擎中,重做日志缓存、重做日志文件都是按照512字节大小的块来进行保存的。 如果一个页中产生的重做日志数量大于512字节,那么需要分割为多个重做日志块进行存储。 此外由于重做日志块的大小和磁盘扇区大小一样都是512个字节,因此重做日志的写入可以保证原子性,不需要doublewrite技术。
重做日志块结构 日志块头 共占用12个字节,
名称
占用字节数
说明
LOG_BLOCK_HDR_NO
4
log buffer 由log block组成,在内部log buffer就像一个数组,log_block_hdr_no来标记这个数据中的位置,它是递增并且循环使用的,占用四个字节。第一位用来判断是否是flush bit,最大的值为2G。
LOG_BLOCK_HDR_DATA_LEN
2
表示log block锁占用的大小。当log block被写满时,该值为0x200,表示使用全部log block空间,也就是占用512字节。
LOG_BLOCK_FIRST_REC_GROUP
2
占用两个字节,表示logblock中第一个日志所在的偏移量,如果该值的大小和log_block_hdr_len相同,表示当前logblock 不包含新的日志。
LOG_BLOCK_CHECKPOINT_NO
4
表示logblock 最后被写入时的检查点的值。
日志内容 日志块内容可以占用512 - 12 - 8 = 492个字节。
日志块尾 共占用8个字节,共有一部分组成,他的值和log_block_hdr_no相同,并在log_block_init中被初始化。
重做日志组 重做日志组中有多个重做日志文件。InnoDB存储引擎只有一个log group。它是一个逻辑上的概念,并没有实际存储的物理文件来表示log group信息。log group是由多个重做日志文件组成的,每个log group中的日志文件大小是相同的。
重做日志文件中存储的是log buffer中保存的log block,因此它也是根据快的方式进行物理存储的管理,每个块的大小与log block一样都是512个字节。在InnoDB存储引擎中,log buffer根据一定的规则将内存中的 log block刷新到磁盘。
事务提交时
log buffer中有一般的内存空间已经被使用时
log checkpoint时
对于log block的写入追加在redo log file 的最后部分,当一个redo log file 被写满时,回接着写入下一个redo log file, 其使用方式是round-robin.
对于log group中的第一个redo log file, 其前2KB的部分保存4个512字节大小的块,存放的内容是:
名称
大小
log file header
512
checkpoint1
512
空
512
checkpoint2
512
对于log group的其他 redo log file ,仅保留这些空间,但不保存这些信息。
redo log file的写入并不是完全顺序的,因为除了log block的写入操作,还需要更新前2KB部分的信息,这些信息对于InnoDB存储引擎的恢复非常重要。
在log file header 后面的部分为InnoDB存储引擎保存的check point值,其设计是交替写入,这样的设计避免了因介质失败而导致无法找到可用的checkpoint情况。
重做日志格式 不同的数据库操作会有丢赢的重做日志格式,由于InnoDB存储引擎的存储管理是基于页的,因此重做日志格式也是基于页的。
通用的头部格式
redo_log_type
space
page_no
redo log body
重做日志类型
表空间ID
页偏移量
日志不同,存储内容不同
LSN Log Sequence Number代表日志序列号,在INnoDB存储引擎中,LSN占用8个字节,并且单调递增。它的含义是:
重做日志写入总量,表示事务写入重做日志的总量,单位是字节。
checkpoint 的位置
页的版本,在每个页头部的fil_page_lsn记录了该页的LSN值,表示LSN最后刷新时的大小。用来判断该页是否需要进行恢复操作。如,页P1的LSN为10000, 而数据库启动时,InnoDB检测到写入重做日志中的LSN为13000,并且该事务已经提交,那么数据库需要进行恢复操作,将重做日志应用到P1中。对于重做日志中LSN小于P1页的LSN,不需要进行重做,表示已经被刷新到该位置。
恢复 InnoDB存储引擎在启动时不管上次数据哭运行时是否正常关闭,都会尝试进行恢复操作,因为重做日志记录的是物理日志,因此恢复的速度比逻辑日志要快很多。同时InnoDB存储引擎自身对恢复做了优化,如顺序读取和并行应用重做日志,这样可以进一步提高数据库恢复的速度。
由于checkpoint表示应刷新到磁盘页上的LSN,因此恢复过程中仅需要恢复检查点开始的日志部分即可。
1 2 create table t(a int, b int, primary key(a), key(b)); insert into t select 1,2;
对于INSERT操作,其记录的是每个页上的变化。由于需要对聚集索引页和辅助索引页进行操作,其记录的重做日志大致为: Page(2,3), offset 32, value 1,2#聚集索引 Page(2,4), offset 64, value 2 #辅助索引
如果插入操作涉及到B+树的分裂,则更多的页需要记录日志。此外,重做日志是物理日志,因此其是幂等的。
undo 在数据库进行修改时,为了防止突然宕机导致最近提交的事务丢失,需要redo log进行恢复。 如果需要对当前事务进行回滚,需要undo log来支持。
redo存放在重做日志中, undo 存放在数据库内部的一个特殊段中,这个段称为undo 段(undo segment)。undo 段位于共享表空间内。
undo 是逻辑日志,只是将数据库逻辑地恢复到原来的样子。例如: 执行一个INSERT 10万条记录的事务,这个事务会导致分配一个新的段(导致表空间增大)。 在执行RollBack时,会将插入的事务进行回滚,但是表空间的大小并不会因此收缩。当InnoDB存储引擎回滚时,它实际上做的事与先前相反的工作。对于每个INSERT,InnoDB存储引擎会完成一个DELETE;对于每个DELETE,InnoDB存储引擎会完成一个INSERT;对于每个UPDATE,InnoDB存储引擎会执行一个相反的UPDATE。
除了回滚操作,undo的另一个作用是mvcc(多版本并发控制),在InnoDB存储引擎中mvcc的实现是通过undo来完成的。当用户读取一行记录时,如果该记录已经被其他事务占用,当前事务可以通过undo读取之前的行版本信息,以此实现非锁定读。
undo log也需要持久性的保护,所以undo log 也会产生redo log。
undo存储管理 InnoDB存储引擎对undo的管理采用段的方式。 InnoDB存储和引擎有rollback segment,每个回滚段中记录了1024 个undo log segment,在每个undo log segment段中进行undo 页的申请。从1.1开始InnoDB支持最大128个rollback segment,故其支持同时在线的事务限制为128 * 1024个。这些所有的rollback segment都存储在共享表空间中。
innodb_undo_directory: 用于设置rollback segment 文件所在的路径,默认为“.”表示当前InnoDB存储引擎的目录。可以设置为共享表空间以外的位置。
innodb_undo_logs:设置rollback segment的个数,默认值为128.
innodb_undo_tablespaces:设置构成rollback segment文件的数量,这样rollback segment可以较为平均地分布在多个文件中。该参数设置后,可以在innodb_undo_directory看到undo前缀的文件,该文件代表rollback segment文件。 undo log segment分配页写入undo log 的这个过程同样需要写入redo log日志。 当事务提交时,InnoDB存储引擎做两件事情: 1)将undo log放入列表中,供以后的purge使用。 2)判断undo log所在的页是否可以重用,如果可以则分配给下一个事务使用。
事务提交以后并不能马上删除undo log以及undo log所在的页。这是因为可能还有其他事务需要通过undo log来得到行记录之前的版本。因此事务提交时将undo log放入一个链表中,然后判断undo页的使用空间是否小于3/4,如果小于3/4则表示该undo页可以被重用,之后新的undo log记录在当前undo log后面。由于存放undo log 的里诶包是以记录进行组织的,而undo 页可能存放着不同事务的undo log,是否可以最终删除undo log以及undolog所在的页由purge线程来判断。purge操作需要涉及磁盘的离散读取操作,是一个比较缓慢的过程。
undo log 格式 在InnoDB存储引擎中,undo log分为: insert undo log / update undo log.
Insert undo log 是指在Insert 操作中产生的undo log,因为Insert操作的记录只对事务本身可见,对其他事务部可见,因此该undo log 可以在事务提交后直接删除,不需要等待purge操作。
*:表示对存储的字段进行压缩。
next: 记录下一个undo log 的位置,通过该值的字节可以知道一个undo log所占用的空间字节数。 start:占用2个字节,记录的是undo log 的开始位置。 type_cmp1:占用1个字节,记录的是undo 的类型,对于insert undo log,值总是11。 undo_no:记录事务的ID table_id:记录undo log所对应的表对象。 接下来记录所有主键的列和值。 在进行rollBack操作室,根据这些纸可以定位到具体的记录,然后进行删除。
update undo log 记录的是对delete和update操作产生的undo log。该undo log 可以能需要提供MVCC机制,因此不能在事务提交时就进行删除。提交时放入undolog 链表中,等待purge线程进行最后的删除操作。
update undo log相对于之前介绍的 insert undo log, 记录的内容更多,所需要占用的空间也更大。
type_cmpl: 12 TRX_UNDO_UPD_EXIST_REC更新non-delete-mark的记录。 13 TRX_UNDO_UPD_DEL_REC将delete的记录标记为not delete 14 TRX_UNDO_DEL_MARK_REC将记录标记为delete
update_vector表示update操作导致发生改变的列。 每个修改的列信息都要记录到undo log中。对于不同的undo log类型,可能还需要记录对索引列所做的修改。
查看undo信息 查看rollback segment
1 DESC INNODB_TRX_ROLLBACK_SEGMENT
查看rollback segment所在的页
1 select segment_id, space, page_no from innodb_trx_rollback_segment;
查看事务所对应的undolog
1 select * from information_schema.INNODB_TRX_UNDO;
通过segment_id 查看当前rollback segment信息
1 select segment_id, insert_undo_list, insert_undo_cached from information_schema.innodb_trx_rollback_segment where segment_id = 2;
delete操作并不直接删除记录,而只是将记录的delete flag标记为1表示已删除,而记录最终的删除是在purge操作中完成的。
update 主键的操作分为两部完成,首先将原主键记录标记为已删除,因此需要产生一个类型为TRX_UNDO_DEL_MARK_REC的undo log, 之后插入一条新的记录,因此需要产生一个类型为TRX_UNDO_INSERT_RED的undo log。
purge delete和update的操作可能并不直接删除原有的数据。
1 delete from t where a = 1;
表t上列a有聚集索引,列b上有辅助索引。对于上述的delete操作仅仅是将主键列等于1的记录delete flag设置为1, 记录并没有被真正的删除还存在于B+树中。
其次对于辅助索引上a=1,b=1的记录同样没有做任何处理,甚至都没有产生undo log。真正删除这行记录的操作被放到了purge操作中。 是因为InnoDB存储引擎支持MVCC,所以记录不能在事务提交时立即进行处理。这时其他事务可能正在引用这行,因此InnoDB 存储引擎需要保存记录之前的版本。是否可以删除需要通过purge来判断。如果这行已经不被任何其他事务引用,那么就可以进行真正的delete操作。
一个页上有多个undo log存在,虽然不代表事务在全局过程中的提交顺序,但是后面的事务产生的undo log总在最后。此外InnoDB存储引擎还有一个history列表,它根据事务提交的顺序,将undo log进行链接。在InnoDB存储引擎的设计中,先提交的事务总在尾端。undo page存放了undo log,由于可以重用,因此一个undo page中可能存放了多个不同事务的undo log。 trx5的灰色阴影表示该undo log还没有被其他事务引用。
在执行purge的过程中,InnoDB存储引擎先从history list中找到第一个需要被清理的记录,trx1, 清理之后InnhoDB存储引擎会在trx1的undo log所在的页中继续寻找是否存在可以被清理的记录。会继续找到trx3, trx5但是发现trx5倍其他事务所引用而不能清理,因此再去history list中国呢查找,发现最尾端的记录trx2,找到trx2所在的页,然后依次吧事务trx6,trx4的记录进行清理。 由于undo page2中的所有页都被清理,因此undo page2可以被重用。
InnoDB存储引擎这种先从historylist中照undo log,然后再从undo page中查找undo log的设计避免了大量的随机读取操作,从而提高了purge的效率。
全局动态参数innodb_purge_batch_size用来设置每次purge操作需要清理的undopage数量。值设置的越大,每次回收的undo page就越多,可供重用的undo page就越多,减少了磁盘存储空间与分配的开销。 但是当之设置的太大,每次需要purge处理更多的undo page,从而导致cpu和磁盘IO过于集中与对undo log的处理,使得性能下降。
当InnoDB的存储引擎压力非常大时,并不能高效地进行purge操作。那么history list的长度会变得越来越长。
全局动态参数innodb_max_purge_lag控制history list的长度, 0: 默认值,不对history list 做任何限制。 大于0时,延缓每一行的DML操作。
全局动态参数innodb_max_purge_lag_delay: 用来控制delay的最大号描述。将innodb_max_purge_lag计算出的值大于当前参数值是,将delay设置为innodb_max_purge_lag_delay, 避免由于purge操作缓慢导致其他SQL线程出现无限制的等待。
group commit 如果事务为非只读事务,每次事务提交时需要进行一次fsync操作,以此保证重做日志都已经写入磁盘。当数据库发生宕机时,可以通过重做日志进行恢复。为了提高fsync的效率,数据库都提供了groupcommit功能,一次fsync可以刷新确保多个事务日志被写入文件。对于InnoDB存储引擎来说,事务提交时会进行两个阶段的操作:
1)修改内存中事务对应的信息,并且将日志写入重做日志缓冲。 2)调用fsync将确保日志都从重做日志缓冲写入磁盘。(将多个事务的重做日志通过一次fsync刷新到磁盘,这样大大的减轻了磁盘的压力,从而提高了数据库的整体性能。对于写入或者更新较为频繁的操作,group commit的效果尤为明显)
在InnoDB1.2版本之前,在开启二进制日志后,InnoDB存储引擎的group Commit都会失效,从而导致性能的下降。在线环境多使用replication环境,因此二进制日志的选项基本都为开启状态,因此该问题尤为显著。导致这个问题的原因是在开启二进制日志后, 为了保证存储引擎层中的事务和二进制日志的一致性,二者之间使用了两阶段事务,其步骤如下。 1)当事务提交时InnoDB存储引擎进行prepare操作。 2)MySQL数据库上层写入二进制日志(一旦该步骤完成,即使后续发生宕机,也能保证事务的提交) 3)InnoDB存储引擎层将日志写入重做日志文件 a) 修改内存中事务对应的信息,并且将日志写入重做日志缓冲。 b) 调用fsync将确保日志都从重做日志缓冲写入磁盘。 每个步骤都需要进行一次fsync才能保证上下两层的数据一致性。 步骤2的fsync由参数sync_binlog控制, 步骤3的fsync由陈安叔innodb_flush_log_at_trx_commit控制。
为了保证MYSQL数据库上层二进制日志的写入顺序和InnoDB层的事务提交顺序一致,MySQL数据库内部使用了prepare_commit_mutex串行锁。启用锁后 3.a步骤不可以在其他事务执行步骤3.b时进行,从而导致了group commit失效。
在Mysql5.6之后,采用了Binary Log Group Commit的方式,不但上层写入的二进制日志时group commit的, InnoDB存储引擎也是group commit的,并且移除了prepare_commit_mutex.
BLGC 在Mysql数据库上层进行提交时首先按照顺序将其放入一个队列中,队列中的第一个事务称为leader, 其他事务称为follower, leader控制这follower的行为。 BLGC分为三个阶段:
Flush 阶段,将每个事务的二进制日志写入内存中。
Sync 阶段,将内存中的二进制日志刷新到磁盘,如果队列中有多个事务,那么仅一次fsync操作就完成了二进制日志的写入。
Commit 阶段,leader 根据顺序调用存储引擎层事务的提交,InnoDB存储引擎本身就支持groupcommit, 因此修复了原先由于锁prepare_commit_mutex导致的group commit 失效的问题。
当有一组事务进行Commit操作时,其他新事务可以进行Flush阶段的操作,从而使GroupCommit不断生效。binlog_max_flush_queue_time用来控制Flush阶段中等待的时间,即使之前的额一组事务完成提交,当前一组的事务也不会马上进入Sync阶段,而是进行等待。这样做的好处是groupCommit的数量更多。但是会导致事务的响应时间变慢。
事务控制语句
START TRANSACTION | BEGIN : 开启事务;
COMMIT:提交事务;
ROLLBACK:回滚事务;
SAVEPOINT identifier: savepoint 允许在事务中创建一个保存点,一个事务中可以有多个savepoint;
RELEASE SAVEPOINT identifier:删除一个事务的保存点,当钱保存点不存在时抛出异常;
ROLLBACK TO 【savepoint】identifier:与savepoint一起使用,可以把事务回滚到标记点,而不回滚在标记点之前的任何工作。(后续还需commit或者rollback才会真正的完成事务)
SET TRANSACTION:设置事务的隔离级别。
隐式提交的SQL语句 执行完这些操作后,都会产生一个隐式的提交操作。 alter database。。。 upgrade data directory name; alter event ; alter procedure; alter table; alter view; create database; create event; create index; create procedure; create table; create trigger; create view; drop database; drop event; drop index; drop procedure; drop table; drop trigger; drop view; rename table; truncate table;
用来隐式地修改MySQL架构的操作: create user; drop user; grant; rename user; revoke; set password;
管理语句: analyze table; cache index; check table; load index into cache; optimize table; repair table;
事务的隔离级别
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE
1 2 3 SET 【GLOBAL|SESSION】 TRASACTION | SOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIABLE }
[mysqld]
1 transaction-isolation=READ-COMMITTED
1 2 select @@tx_isolation;//查看当前会话的事务隔离级别 select @@global.tx_isolation; //查看全局事务隔离级别
InnoDB默认隔离级别为 REPEATABLE READ,使用Next-Key Lock 锁算法, 避免了幻读的产生,因此在改隔离级别下久已经能保证事务隔离性的要求,达到标准SQL的SERIALIZABLE的隔离级别。 隔离级别越低,事务请求的锁越少或者保持锁的时间就越短。
在SERIALIABLE隔离级别, INNODB会对每个SELECT语句后自动加上 lock in share mode的共享锁。 因此在这个隔离级别下,读占用了锁, 对一致性的非锁定读就不再予以支持。 Serialiable隔离级别一般用在分布式事务上。
##分布式事务
InnoDB存储引擎提供了对XA事务的支持,并通过XA事务来支持分布式事务的实现。分布式事务是多个独立的事务资源参与到一个全局的事务中。 全局事务要求在其中的所有参与的事务要么都提交,要么都回滚。在使用分布式事务时,InnoDB存储引擎的事务隔离级别必须设置为SERIALIZABLE。
XA事务由一个或者多个资源管理器、一个事务管理器以及一个应用程序组成。
资源管理器:提供访问事务资源的方法。通常一个数据库就是一个资源管理器。
事务管理器:协调参与全局事务中的各个事务,需要和参与全局事务的所有资源管理器进行通信。
应用程序:定义事务的边界,指定全局事务中的操作。
不好的事务习惯
在循环中提交事务(每次提交都会写一次 redo log,导致性能变慢)
使用自动提交
使用自动回滚长事务