事务调度与长事务

共 38 题
📑 题目列表 38 题
#
★★★

1. DDL 在 MySQL 中的隐式提交,执行 CREATE TABLE 自动提交事务?

请说明 MySQL 中 DDL 的隐式提交行为,执行 CREATE TABLE 是否自动提交事务?

  • MySQL 中 DDL 语句会隐式提交当前事务。
  • CREATE TABLE、ALTER TABLE、DROP 等触发隐式提交。
  • 无法回滚 DDL。

在 MySQL 中,DDL 语句(CREATE、ALTER、DROP、TRUNCATE 等)会触发隐式提交(implicit commit):执行 DDL 前,当前事务会被自动提交,DDL 本身也不可回滚。因此执行 CREATE TABLE 会自动提交当前事务,且 CREATE TABLE 成功后无法用 ROLLBACK 撤销。这是 MySQL 与 PostgreSQL 的重要差异(PostgreSQL 支持事务性 DDL,可回滚)。MySQL 隐式提交的后果:若在事务中执行 DDL,之前未提交的修改会被强制提交;DDL 出错不能回滚。因此迁移脚本需注意 DDL 的不可回滚性,分批执行或在 DDL 前显式提交。理解 MySQL 隐式提交是事务管理的重要细节。

MySQL 的 DDL 隐式提交使 DDL 不可回滚,且会强制提交当前事务。这是与 PostgreSQL 事务性 DDL 的核心差异。

#
★★★

2. PostgreSQL 中 DDL 的事务性,CREATE TABLE 可回滚?

请说明 PostgreSQL 中 DDL 的事务性,CREATE TABLE 是否可回滚?

  • PostgreSQL 支持事务性 DDL。
  • DDL 与 DML 在同一事务中,可一起回滚。
  • CREATE TABLE 失败/回滚可撤销。

PostgreSQL 支持事务性 DDL(transactional DDL):DDL 语句(CREATE TABLE、ALTER TABLE、DROP 等)与 DML 一样在事务中执行,可随事务一起提交或回滚。因此 CREATE TABLE 在事务中执行后,若事务回滚,表创建也被撤销;若事务提交,表创建才生效。这与 MySQL 的隐式提交形成对比。事务性 DDL 的好处:迁移脚本可把 DDL 与相关 DML 放在一个事务中,保证原子性(要么全部成功要么全部回滚),出错可回滚。但注意:PostgreSQL 的 DDL 仍会获取锁,且某些 DDL 可能阻塞查询。理解事务性 DDL 是 PostgreSQL 迁移与回滚策略的基础。

PostgreSQL 的 DDL 是事务性的,可随事务回滚。这为迁移脚本提供了原子性与回滚能力,与 MySQL 隐式提交不同。

#
★★★

3. 隐式提交的常见陷阱,autocommit、DDL、函数异常?

请说明隐式提交的常见陷阱,包括 autocommit、DDL、函数异常?

  • autocommit 开启时单条语句自动提交。
  • DDL 触发隐式提交。
  • 函数异常可能中断事务。

隐式提交的常见陷阱包括:一是 autocommit 开启时,每条语句自动提交,多语句操作无法构成原子事务,若误以为在事务中,中途失败无法回滚;二是 DDL 隐式提交(MySQL),事务中执行 DDL 会强制提交之前修改,导致原子性破坏;三是函数/存储过程异常:若函数内含隐式提交或异常处理不当,可能破坏事务边界。陷阱后果:误以为多语句在一个事务中,实际被隐式提交拆分,部分成功部分失败。规避方法:显式使用 BEGIN/COMMIT 控制事务、关闭 autocommit、避免在事务中混入 DDL、合理处理函数异常与保存点。理解隐式提交陷阱对正确管理事务至关重要。

隐式提交陷阱源于 autocommit、DDL 隐式提交、函数异常。它们都可能意外拆分事务、破坏原子性。

#
★★★

4. PostgreSQL DDL 的事务性?

请说明 PostgreSQL DDL 的事务性及其对迁移脚本的意义?

  • DDL 在事务中执行,可回滚。
  • 迁移脚本可原子执行。
  • 支持 DDL 与 DML 同事务。

PostgreSQL 的 DDL 是事务性的:DDL 语句在事务中执行,随事务提交或回滚。这意味着迁移脚本可以包含 DDL 与 DML,整体在一个事务中原子执行——若脚本中途出错,回滚整个事务,包括已执行的 DDL(如已建的表、已加的索引)都被撤销,保证迁移的原子性与一致性。这对生产环境迁移尤其重要:避免"一半成功一半失败"的脏状态。相比 MySQL 的 DDL 隐式提交,PostgreSQL 的事务性 DDL 提供更强回滚能力。但注意:DDL 在事务中会持锁,可能阻塞;且某些 DDL 的锁需要事务结束才释放。合理利用事务性 DDL 可编写安全、可回滚的迁移脚本。

事务性 DDL 让迁移脚本原子执行、可回滚。这是 PostgreSQL 迁移策略的核心优势,与 MySQL 隐式提交形成对比。

#
★★★

5. 2PC 的单点故障(协调者宕机)与悬挂事务(in-doubt transaction)?

请说明 2PC 的单点故障(协调者宕机)与悬挂事务(in-doubt transaction)问题?

  • 协调者是 2PC 的单点故障。
  • 协调者宕机导致悬挂事务。
  • 通过日志与恢复解决。

两阶段提交(2PC)中协调者(coordinator)是单点故障:若协调者在事务执行中宕机,参与者不知道是否提交,事务进入悬挂状态(in-doubt transaction)。悬挂事务的参与者持有锁,可能阻塞其他事务,且无法自动决定提交或回滚。解决方式:协调者需持久化事务日志(写日志记录决定),崩溃恢复时从日志恢复决策;参与者可查询协调者状态或超时后采取策略(通常等待协调者恢复)。分布式事务管理器(如 XA、Seata)通过日志与恢复机制处理悬挂事务。悬挂事务的管理是 2PC 可靠性的关键,也是分布式事务的难点之一。

协调者宕机导致悬挂事务,参与者无法确定提交/回滚。靠协调者日志与恢复解决。这是 2PC 的典型故障场景。

#
★★★

6. Saga 模式,长事务拆分为多个本地事务 + 补偿?

请说明 Saga 模式的原理,长事务如何拆分为多个本地事务并用补偿实现最终一致性?

  • Saga 把长事务拆为多个本地事务。
  • 每个本地事务有对应补偿事务。
  • 失败时逆序执行补偿。

Saga 模式把分布式长事务拆分为多个本地事务(每个操作在一个节点上独立提交),并为每个本地事务定义对应的补偿事务(compensation)。Saga 按顺序执行各本地事务;若某个本地事务失败,则逆序执行已成功事务的补偿事务,回滚已达成的操作,实现最终一致性。Saga 有两种协调方式:编排(choreography,事务间通过事件驱动)与编配(orchestration,中央 Saga 协调器控制)。它不保证全局原子性(中间状态对外可见),但通过补偿实现最终一致。补偿事务需幂等,且需考虑补偿失败。Saga 适合长事务、跨服务、可接受短暂中间状态的场景,避免 2PC 的阻塞与单点问题。

Saga 核心是"本地事务 + 补偿",失败时逆序补偿。它牺牲全局原子性换取最终一致与高可用,是分布式事务常用模式。

#
★★★

7. TCC(Try-Confirm-Cancel)补偿事务模式?

请说明 TCC(Try-Confirm-Cancel)补偿事务模式的工作原理?

  • TCC 分 Try、Confirm、Cancel 三阶段。
  • Try 预留资源,Confirm 确认,Cancel 取消。
  • 面向业务资源的事务模式。

TCC(Try-Confirm-Cancel)是补偿事务模式,把每个业务操作拆为三个阶段:Try(预留资源):检查并预留本次操作所需资源(如冻结余额、预占库存),不实际提交;Confirm(确认):Try 全部成功后,执行真正提交(扣减、发货),不可回滚;Cancel(取消):Try 失败或业务取消时,释放预留资源(回滚冻结)。TCC 通过业务层实现这三个阶段,保证最终一致性,且比 Saga 更严格(Try 预留资源减少冲突)。TCC 需要业务实现幂等与空回滚处理(如 Try 未执行时 Cancel 需忽略)。相比 Saga 的补偿,TCC 的 Try 预留资源能减少并发冲突。适合资源预占类业务(余额、库存、优惠券)。

TCC 分 Try 预留、Confirm 确认、Cancel 取消三阶段。通过预留资源减少冲突,业务层实现幂等与空回滚。

#
★★★

8. XA 事务的标准(JTA、XA 规范)的实现?

请说明 XA 事务的标准(JTA、XA 规范)及其实现?

  • XA 是分布式事务规范,基于 2PC。
  • JTA 是 Java 的 XA 事务接口。
  • 资源管理器(数据库)参与 XA。

XA 是处理分布式事务的标准规范(由 X/Open 定义),基于两阶段提交(2PC)。它定义了事务管理器(TM)、资源管理器(RM,如数据库)与 XA 接口:xa_start、xa_prepare、xa_commit、xa_rollback 等。JTA(Java Transaction API)是 Java 对 XA 事务的规范,提供 UserTransaction、TransactionManager 接口,应用通过 JTA 参与分布式事务。实现上,数据库(MySQL、Oracle、PostgreSQL)通过原生 XA 支持(如 MySQL 的 XA START/END/PREPARE/COMMIT)作为资源管理器参与。XA 流程:TM 协调多个 RM,prepare 阶段各 RM 准备并持久化,commit 阶段统一提交。XA 保证强一致,但性能开销大、有阻塞与单点问题(协调者)。JTA 是 Java 生态使用 XA 的标准方式。

XA 是基于 2PC 的分布式事务规范,JTA 是 Java 版 XA 接口。理解 XA 的阶段与 TM/RM 角色是核心。

#
★★★

9. 两阶段提交(2PC, Two-Phase Commit)的协调者-参与者模型?

请说明两阶段提交(2PC)的协调者-参与者模型?

  • 协调者(coordinator)与参与者(participants)。
  • 准备阶段(prepare)与提交阶段(commit)。
  • 全体一致决策。

两阶段提交(2PC)的模型是协调者(coordinator)管理多个参与者(participants,各资源管理器/数据库)。两个阶段:准备阶段(prepare):协调者向所有参与者发送 prepare 请求,参与者执行事务操作并写日志,但暂不提交,向协调者报告"可以提交"或"准备失败";若任一参与者返回失败,协调者决定回滚。提交阶段(commit):所有参与者都准备好了,协调者向所有参与者发送 commit 请求,参与者提交并释放锁;若有失败,协调者发送 abort,参与者回滚。协调者负责决策,参与者负责执行。2PC 保证所有参与者要么都提交要么都回滚(原子性),但协调者是单点,且阻塞问题(参与者等待协调者)。这是分布式强一致的基础协议。

2PC 是协调者-参与者模型,prepare 全体准备、commit 统一提交。任一失败则回滚,保证原子性,但协调者单点。

#
★★★

10. Seata AT 模式如何通过全局锁 + 本地 undo log 实现自动补偿?它面临的脏写问题是什么,TCC 的空回滚、悬挂与幂等又如何防御?

请说明 Seata AT 模式如何通过全局锁与本地 undo log 实现自动补偿,其脏写问题,以及 TCC 的空回滚、悬挂与幂等防御?

  • AT 模式:全局锁 + 本地 undo log 自动补偿。
  • 脏写问题:分支事务基于过期数据写。
  • TCC 防空回滚、悬挂、幂等。

Seata AT 模式在分布式事务中,每个分支事务在本地数据库执行 SQL 并生成 undo log(记录修改前后的数据镜像);全局事务提交前,通过全局锁(GlobalLock)防止其他分支并发修改冲突。提交时各分支删除 undo log;回滚时用 undo log 反向补偿(恢复旧值),实现自动补偿。脏写问题:AT 模式下分支事务可能基于过期的数据快照写(两个全局事务交错),导致全局锁无法完全防止脏写,需依赖全局锁与隔离级别配合。TCC 的防御:空回滚——Try 未执行时 Cancel 需忽略(通过事务记录判断);悬挂——Confirm/Cancel 先于 Try 到达时需处理(记录状态);幂等——Confirm/Cancel 重复执行需幂等(用事务 ID 或状态去重)。这些防御是 TCC 正确性的关键。

AT 用全局锁+undo log 自动补偿,但存在脏写风险。TCC 需防空回滚、悬挂、幂等,通过状态记录与幂等机制。

#
★★★

11. 本地消息表与 RocketMQ 事务消息(half message + 状态回查)分别如何实现最终一致性?二者在可靠性、耦合度与运维成本上有何差异?

请说明本地消息表与 RocketMQ 事务消息(half message + 状态回查)如何实现最终一致性,以及两者的可靠性、耦合度与运维成本差异?

  • 本地消息表:本地事务写消息表 + 定时投递。
  • RocketMQ 事务消息:half message + 状态回查。
  • 可靠性、耦合度、运维成本对比。

本地消息表:业务在本地事务中同时写业务数据与消息表(同一本地库),提交后由定时任务把消息投递到 MQ,投递成功后删除消息。保证"业务与消息同事务",实现最终一致性。RocketMQ 事务消息:发送 half message(半消息,消费者不可见),本地执行事务,提交/回滚后调用 MQ 确认,若本地事务状态未知,MQ 通过状态回查(check)询问业务方决策。二者都实现最终一致性。差异:可靠性——本地消息表依赖本地 DB 与定时任务,事务消息由 MQ 保证(half+回查更可靠);耦合度——本地消息表需业务自建消息表与定时任务,耦合高;事务消息耦合 MQ,业务更简单;运维成本——本地消息表需自维护表与任务,事务消息依赖 MQ 的可靠性(需 MQ 高可用)。总体事务消息更便利但依赖 MQ,本地消息表自包含但实现复杂。

两者都保证"业务与消息转发一致"实现最终一致。本地消息表自建表+任务,事务消息用 half+回查,耦合与运维成本不同。

#
★★★

12. MySQL XA(2PC)的性能开销来自哪里(binlog 与 redo 两阶段落盘、锁持有到 COMMIT 之后)?为什么高并发互联网场景很少直接使用 XA?

请说明 MySQL XA(2PC)的性能开销来源,以及为何高并发互联网场景很少直接使用 XA?

  • binlog 与 redo 两阶段落盘。
  • 锁持有到 commit 之后。
  • 协调者开销与阻塞。

MySQL XA(2PC)的性能开销主要来自:一是 binlog 与 redo log 两阶段落盘,XA 提交需要 prepare 阶段把事务写入 redo 并持久化,commit 阶段再写 binlog,两阶段落盘增加 fsync 次数;二是锁持有时间延长,prepare 后锁仍持有,直到 commit 才释放,长锁增加阻塞与死锁;三是协调者协调多个参与者,有网络与调度开销;四是协调者单点与阻塞问题。因此高并发互联网场景很少直接使用 XA:一是性能开销大(两阶段落盘、长锁),无法支撑高吞吐;二是强一致阻塞与协调者单点降低可用性;三是需要所有参与者都支持 XA 且延迟敏感。互联网通常用最终一致方案(Saga、TCC、消息)替代 XA,换取可用性与性能。

XA 开销来自两阶段落盘、长锁持有、协调者开销。高并发场景用最终一致方案替代 XA 换取性能与可用性。

#
★★★

13. 两阶段锁(2PL, Two-Phase Locking)与可串行化的关系?

请说明两阶段锁(2PL)与可串行化的关系?

  • 2PL 分增长期与收缩期。
  • 2PL 保证冲突可串行化。
  • 严格 2PL 防级联回滚。

两阶段锁(2PL, Two-Phase Locking)是保证可串行化的锁协议。它分两个阶段:增长期(growing phase):事务只能获取锁,不能释放锁;收缩期(shrinking phase):事务只能释放锁,不能获取新锁。2PL 保证冲突可串行化(conflict-serializable):任何遵循 2PL 的调度,其冲突图无环,等价于串行调度。严格 2PL(strict 2PL)进一步加强:事务提交或回滚后才释放锁,防止级联回滚(cascade rollback)。2PL 是悲观并发控制的基础,数据库通过 2PL 保证可串行化。但 2PL 会导致阻塞与死锁(锁冲突),需死锁检测/超时。2PL 与可串行化的关系:2PL 是满足可串行化的充分条件,但不是必要条件(有些可串行化调度不遵循 2PL)。

2PL 分增长/收缩期,保证冲突可串行化。严格 2PL 防级联回滚。2PL 是可串行化的充分条件。

#
★★★

14. 严格两阶段锁(Strict 2PL)防止级联回滚?

请说明严格两阶段锁(Strict 2PL)如何防止级联回滚?

  • 级联回滚:一个事务回滚导致依赖它的其他事务回滚。
  • 严格 2PL 在提交后才释放锁。
  • 避免读到未提交数据。

级联回滚(cascade rollback)指:一个事务回滚,导致读取了该事务未提交数据(且尚未提交)的其他事务也不得不回滚,回滚像多米诺骨牌一样传播。严格 2PL(strict 2PL)规定:事务在提交或回滚之前不释放任何锁(尤其是写锁)。这样其他事务无法在事务提交前读取其未提交的写数据,从而避免读到未提交数据带来的级联回滚。严格 2PL 是 2PL 的加强版,在保证可串行化的同时,通过"提交后才释放锁"消除级联回滚。实际数据库(如 InnoDB)采用的锁协议通常满足严格 2PL。理解严格 2PL 与级联回滚的关系是并发控制正确性的关键。

严格 2PL 在提交后才释放锁,阻止读到未提交数据,从而防止级联回滚。这是它相对普通 2PL 的加强。

#
★★★

15. 事务调度(Schedule)的概念,串行调度(Serial)与可串行化调度?

请说明事务调度(Schedule)的概念,以及串行调度与可串行化调度的区别?

  • 调度是并发事务操作的执行顺序。
  • 串行调度:事务不交错。
  • 可串行化调度:等价于某串行调度。

事务调度(schedule)是多个并发事务操作的执行顺序(即事务之间竞争和交错执行的具体序列)。串行调度(serial schedule):事务一个接一个执行,不交错,结果等价于逐个执行,总是正确的。可串行化调度(serializable schedule):事务交错执行,但结果等价于某个串行调度,因此数据正确。数据库的隔离级别保证可串行化调度(SERIALIZABLE 级别)。判断可串行化:冲突可串行化(冲突等价于某串行调度)或视图可串行化(视图等价)。DBMS 通过并发控制(锁、MVCC、时间戳)调度事务,保证可串行化。理解调度与可串行化是事务并发理论的核心。

调度是事务执行顺序,串行调度不交错,可串行化调度结果等价于串行。数据库通过并发控制保证可串行化调度。

#
★★★

16. 可串行化(Serializable)的两种判定,冲突等价(Conflict Equivalence)与视图等价(View Equivalence)?

请说明可串行化的两种判定:冲突等价与视图等价?

  • 冲突等价:冲突操作顺序一致。
  • 视图等价:每事务读到的值与最终写一致。
  • 冲突可串行化是视图可串行化的子集。

可串行化判定有两种等价:冲突等价(conflict equivalence)与视图等价(view equivalence)。冲突等价:两个调度中,冲突操作(读写同一数据、至少一个写)的相对顺序一致,则冲突等价;若某调度冲突等价于某串行调度,则冲突可串行化。视图等价:两个调度中,每个事务读到的值相同(读依赖一致),且最终写集一致;若某调度视图等价于某串行调度,则视图可串行化。冲突可串行化是视图可串行化的子集(冲突可串行化蕴含视图可串行化,反之不一定)。冲突可串行化易用冲突图检测(无环),是数据库常用的判定;视图可串行化更难检测。2PL 保证冲突可串行化。

冲突等价看冲突操作顺序,视图等价看读值与最终写。冲突可串行化是视图可串行化的子集,用冲突图检测。

#
★★★

17. 时间戳排序(Timestamp Ordering, TO)的乐观并发控制?

请说明时间戳排序(Timestamp Ordering, TO)的乐观并发控制原理?

  • 时间戳决定事务顺序。
  • 冲突操作按时间戳排序。
  • 常用乐观并发控制。

时间戳排序(Timestamp Ordering, TO)是一种乐观并发控制:每个事务分配唯一时间戳,决定其串行顺序;事务的读写操作按时间戳顺序执行,冲突时(如后时间戳事务读/写前时间戳事务已写的数据)可能回滚后时间戳事务。TO 不通过锁串行化,而是通过时间戳判断冲突,允许事务并发执行,冲突时回滚较"新"的事务。TO 保证冲突可串行化(冲突操作按时间戳排序)。乐观并发控制(OCC)通常基于版本号/时间戳,在提交时校验冲突,冲突则回滚重试。TO 适合读多写少、冲突少的场景,避免锁开销,但冲突多时回滚频繁。相比悲观锁(2PL),TO 是乐观的,无阻塞等待。

时间戳排序按时间戳决定事务顺序,冲突时回滚。是乐观并发控制,避免锁阻塞,但冲突多时回滚频繁。

#
★★★

18. 两阶段锁(2PL)?

请说明两阶段锁(2PL)的基本原理与性质?

  • 增长期获取锁、收缩期释放锁。
  • 保证冲突可串行化。
  • 可能死锁。

两阶段锁(2PL, Two-Phase Locking)是悲观并发控制协议。它要求每个事务的锁操作分两个阶段:增长期(growing phase):事务只获取锁,不释放;收缩期(shrinking phase):事务只释放锁,不获取新锁。2PL 保证冲突可串行化:任何遵循 2PL 的调度,冲突图无环,等价于串行调度。严格 2PL 要求提交后才释放锁,防级联回滚。2PL 的代价:锁冲突导致阻塞、可能死锁(需死锁检测/超时)。2PL 是数据库解决写写冲突的基础,InnoDB 的行锁、页面锁等遵循 2PL 思想。但它导致的阻塞与死锁是悲观并发控制的固有代价。

2PL 分增长/收缩期,保证冲突可串行化,但可能死锁。严格 2PL 防级联回滚。是悲观并发控制基础。

#
★★★

19. MySQL InnoDB 中 SAVEPOINT 与嵌套事务的差异?

请说明 MySQL InnoDB 中 SAVEPOINT 与嵌套事务的差异?

  • InnoDB 不支持真正的嵌套事务。
  • SAVEPOINT 提供部分回滚。
  • 内部回滚不影响外部。

MySQL InnoDB 不支持真正的嵌套事务(独立子事务),而是通过 SAVEPOINT 实现"事务内部分回滚"。SAVEPOINT 在事务中设置保存点,ROLLBACK TO SAVEPOINT sp 回滚到该点,撤销之后的操作(释放该点之后的锁、undo 到该点),但事务本身不结束,后续可继续执行或最终 COMMIT。嵌套事务理论要求内部事务可独立提交/回滚,InnoDB 的 SAVEPOINT 只是事务内的标记,不具备独立提交语义。因此差异:SAVEPOINT 是"事务内回滚点",嵌套事务是"独立子事务"。使用 SAVEPOINT 实现部分回滚,避免整体回滚。理解差异有助于正确使用事务内回滚。

InnoDB 无真正嵌套事务,SAVEPOINT 提供事务内部分回滚。差异是"回滚点" vs "独立子事务"。

BEGIN;
SAVEPOINT sp1;
UPDATE t SET a = 1 WHERE id = 1;
ROLLBACK TO SAVEPOINT sp1;  -- 撤销 UPDATE,保留事务
COMMIT;
#
★★★

20. SQL 标准中的嵌套事务支持(SAVEPOINT 的有限近似)?

请说明 SQL 标准对嵌套事务的支持,以及 SAVEPOINT 为何是有限近似?

  • SQL 标准不要求真正的嵌套事务。
  • SAVEPOINT 提供部分回滚近似。
  • 回滚到保存点撤销之后操作。

SQL 标准不要求数据库支持真正的嵌套事务,而是通过 SAVEPOINT(保存点)提供"事务内部分回滚"的近似能力。SAVEPOINT 在事务中设置保存点,ROLLBACK TO SAVEPOINT 回滚到该点,撤销之后的所有操作(包括 DML 与锁),但继续当前事务。这是对嵌套事务的有限近似:它不能提供"内部子事务独立提交/回滚"的完整语义,只能回滚到指定点。真正的嵌套事务(如内层事务独立提交不影响外层)未被标准强制,多数数据库用 SAVEPOINT 模拟。有限近似体现在:SAVEPOINT 的回滚是"撤销到点"而非"提交子事务",且保存点数量与嵌套层级有限。理解 SAVEPOINT 的有限性对事务设计重要。

SQL 标准不要求真正嵌套事务,SAVEPOINT 提供部分回滚近似。有限近似在于不能独立提交子事务。

#
★★★

21. 长事务/大事务对主从复制延迟的影响(binlog/WAL 单事务串行应用)与治理

请说明长事务/大事务如何影响主从复制延迟,以及治理方法?

  • 大事务产生大量 binlog/WAL。
  • 从库单事务串行应用,延迟放大。
  • 治理:拆分事务、减少大事务。

主从复制延迟的影响:大事务/长事务会产生大量 binlog(MySQL)或 WAL(PostgreSQL),从库在应用这些日志时,单事务是串行应用的(同一事务的日志需按顺序应用),大事务应用耗时极长,导致从库延迟显著放大。此外,长事务持锁长,可能阻塞复制。治理方法:拆分大事务为多个小事务(减少单事务数据量);避免长事务长时间持锁;合理设置 binlog 相关参数;对从库监控延迟并告警;使用并行复制(MySQL 的 MTS 多线程复制,可并行应用不同事务,但同一事务仍串行);大表 DML 分批执行。减少主库大事务是降低复制延迟的根本。

大事务产生大量日志,从库单事务串行应用导致延迟放大。治理是拆分事务、减少大事务、并行复制。

#
★★

22. 嵌套事务(Nested Transaction)的概念,内部事务回滚不影响外部?

请说明嵌套事务(Nested Transaction)的概念,内部事务回滚为何不影响外部?

  • 嵌套事务是独立子事务。
  • 内部回滚不影响外部。
  • 数据库通常用 SAVEPOINT 近似。

嵌套事务(nested transaction)指一个事务内部包含多个子事务,子事务可独立提交或回滚。理想语义:内部子事务回滚不影响外部事务(外部仍可继续或提交);内部子事务提交也不影响外部(外部提交才最终生效)。但大多数关系数据库(PostgreSQL、MySQL)不原生支持真正的嵌套事务,而是用 SAVEPOINT 近似:SAVEPOINT 回滚撤销之后的操作,不结束外部事务,近似"内部回滚不影响外部"。真正的嵌套事务(如某些研究型或 NoSQL)内部子事务独立生命周期。理解嵌套事务概念与 SAVEPOINT 近似的关系,是事务嵌套设计的核心。

嵌套事务是独立子事务,内部回滚不影响外部。数据库用 SAVEPOINT 近似此语义。

#
★★

23. 长事务对 MVCC 的影响,版本膨胀(Version Bloat)、VACUUM 阻塞?

请说明长事务对 MVCC 的影响,包括版本膨胀与 VACUUM 阻塞?

  • 长事务阻塞旧版本回收。
  • 版本膨胀占空间。
  • VACUUM 无法清理。

长事务对 MVCC 的影响显著。一是版本膨胀(version bloat):MVCC 中,旧版本需保留供活跃事务读取,长事务作为"最老活跃事务"(PostgreSQL 的 oldest xmin),使 VACUUM 无法清理其之后产生的旧版本,导致表和索引中旧版本堆积,占用大量空间,表膨胀。二是 VACUUM 阻塞/无法推进:VACUUM 只能清理早于 oldest xmin 的版本,长事务拖延 oldest xmin,VACUUM 无法有效回收空间。MySQL 中则是 undo log 无法被 purge,undo 膨胀。后果:磁盘占用增长、查询变慢(扫描更多版本)、索引膨胀。治理:避免长事务、及时提交、监控并清理长事务。理解长事务对 MVCC 的影响是版本膨胀治理的关键。

长事务拖延最老活跃事务,阻塞旧版本回收,导致版本膨胀与 VACUUM 无法推进。这是 MVCC 的固有代价。

#
★★

24. 长事务的检测,pg_stat_activity、INFORMATION_SCHEMA.INNODB_TRX?

请说明长事务的检测方法,包括 pg_stat_activity 与 INFORMATION_SCHEMA.INNODB_TRX?

  • PostgreSQL 用 pg_stat_activity 检测。
  • MySQL 用 INFORMATION_SCHEMA.INNODB_TRX 检测。
  • 通过事务开始时间判断长事务。

检测长事务:PostgreSQL 查 pg_stat_activity,关注 state(active/idle in transaction)、xact_start(事务开始时间),若 xact_start 很久或 state 为 idle in transaction 时间长,即长事务/空闲事务。MySQL 查 information_schema.innodb_trx,关注 trx_started(事务开始时间)、trx_state、trx_rows_locked 等,trx_started 很久的事务为长事务。也可用 SHOW PROCESSLIST 或 performance_schema 查看。检测到长事务后,及时处理(提交、终止、设置超时)。定期监控长事务并告警是运维必备。理解检测方法有助于及时治理长事务。

PostgreSQL 用 pg_stat_activity 的 xact_start,MySQL 用 innodb_trx 的 trx_started 检测长事务。监控并告警是治理关键。

-- PostgreSQL
SELECT pid, state, xact_start, now()-xact_start AS duration FROM pg_stat_activity WHERE state <> 'idle';
-- MySQL
SELECT trx_id, trx_started, trx_state FROM information_schema.innodb_trx;
#
★★

25. 长事务(Long Transaction)的成因,未提交事务、慢查询、客户端异常?

请说明长事务的成因,包括未提交事务、慢查询、客户端异常?

  • 未提交事务长时间挂起。
  • 慢查询执行过久。
  • 客户端异常/连接中断未提交。

长事务的常见成因:一是未提交事务:客户端开启事务后长时间不提交(如连接池连接未释放、代码忘记 COMMIT),事务挂起。二是慢查询:事务内执行了超长时间的查询或大量 DML,事务本身耗时长。三是客户端异常:客户端崩溃、网络中断或应用未正确处理,导致事务一直未提交(连接仍挂着,事务未结束)。四是空闲事务:事务开了但长时间无操作(idle in transaction)。这些成因都导致事务长时间存在,引发版本膨胀、锁持有、复制延迟等。治理:及时提交、优化慢查询、设置事务超时(idle_in_transaction_session_timeout)、监控连接情况。理解成因有助于针对性预防长事务。

长事务成因是未提交、慢查询、客户端异常。理解成因并通过超时、监控、提交纪律治理是核心。

#
★★

26. Oracle 中 DDL 的隐式提交行为?

请说明 Oracle 中 DDL 的隐式提交行为?

  • Oracle 的 DDL 隐式提交。
  • 执行 DDL 前自动提交当前事务。
  • DDL 不可回滚。

Oracle 中,DDL 语句(CREATE、ALTER、DROP、TRUNCATE 等)会触发隐式提交(implicit commit):执行 DDL 前,Oracle 自动提交当前所有未提交的事务,然后执行 DDL,DDL 本身不可回滚。这与 MySQL 的隐式提交类似,与 PostgreSQL 的事务性 DDL 不同。后果:事务中执行 DDL 会强制提交之前的修改,破坏原子性;DDL 出错无法回滚。因此 Oracle 迁移脚本需注意 DDL 的不可回滚性,在 DDL 前显式提交或分批执行。Oracle 与 MySQL 的 DDL 隐式提交行为一致,PostgreSQL 支持事务性 DDL。理解 Oracle 的隐式提交是数据库迁移与事务管理的重要细节。

Oracle 的 DDL 隐式提交,与 MySQL 一致,与 PostgreSQL 事务性 DDL 相反。理解其对迁移脚本的影响是关键。

#
★★

27. SAVEPOINT 的语法,SAVEPOINT sp1、ROLLBACK TO SAVEPOINT sp1?

请说明 SAVEPOINT 的语法,包括 SAVEPOINT、ROLLBACK TO、RELEASE?

  • SAVEPOINT sp 设置保存点。
  • ROLLBACK TO SAVEPOINT sp 回滚到保存点。
  • RELEASE SAVEPOINT 释放保存点。

SAVEPOINT 语法:SAVEPOINT sp1 设置名为 sp1 的保存点;ROLLBACK TO SAVEPOINT sp1 回滚到该保存点,撤销保存点之后的所有操作(释放锁、undo 到该点),但事务继续;RELEASE SAVEPOINT sp1 释放保存点(删除标记,但已执行的操作保留)。回滚到保存点后,保存点仍存在,可再次使用或不使用。SAVEPOINT 用于事务内部分回滚,避免整体回滚。它不结束事务,之后可继续操作或最终 COMMIT。理解语法与语义(回滚/释放的区别)是事务内部分回滚的基础。

SAVEPOINT 设置保存点,ROLLBACK TO 回滚到点,RELEASE 释放点。回滚到点后事务继续,不结束。

BEGIN;
SAVEPOINT sp1;
UPDATE t SET a = 1 WHERE id = 1;
ROLLBACK TO SAVEPOINT sp1;   -- 撤销 UPDATE
-- 事务继续
COMMIT;
#
★★

28. 最终一致性(Eventual Consistency)vs 强一致性?

请说明最终一致性(Eventual Consistency)与强一致性(Strong Consistency)的区别?

  • 强一致:读立即看到最新已提交。
  • 最终一致:短暂不一致后收敛。
  • 适用场景与权衡。

强一致性(strong consistency):任何时刻读到的都是最新已提交数据,读与写线性一致,如单机数据库事务(SERIALIZABLE)。最终一致性(eventual consistency):系统允许短暂不一致,但保证在无新写入后,经过一段时间所有副本/读取收敛到一致状态,如分布式系统、缓存、异步复制。差异:强一致提供即时一致性但性能/可用性受限(需同步协调);最终一致提供高可用与高性能,但需容忍短暂不一致。分布式系统在 CAP 下常牺牲强一致换取可用性,采用最终一致。选择取决于业务:强一致适合资金类强一致业务,最终一致适合非实时的数据同步。最终一致性通过消息、补偿、对账等实现。

强一致读最新,最终一致短暂不一致后收敛。分布式系统常牺牲强一致换取可用性,是 CAP 的取舍。

#
★★

29. 最大努力通知(有限次重试 + 降级)与定期对账补偿机制如何配合,覆盖非实时跨系统一致性需求?

请说明最大努力通知(有限次重试 + 降级)与定期对账补偿如何配合,覆盖非实时跨系统一致性?

  • 最大努力通知:有限次重试 + 降级。
  • 定期对账:核对差异并补偿。
  • 兜底非实时一致性。

最大努力通知(best-effort notification)是补偿方案的简化:发送/调用接口进行有限次重试(如 3 次),多次失败则降级(记录失败、告警、人工介入),不保证发送成功。它适合对实时性要求低的场景。定期对账(reconciliation)补偿:定时任务(如每日)核对两个系统的数据差异,发现不一致时执行补偿(补发、修正、回滚),兜底最大努力通知的漏网之鱼。两者配合:最大努力通知先尽力保证即时一致性,定期对账作为兜底,在非实时窗口内发现并修复不一致,实现最终一致性。这种方案覆盖"非实时、可接受短暂不一致"的跨系统一致性需求,成本低、实现简单,适合财务对账、订单同步等场景。

最大努力通知是有限重试+降级,定期对账是兜底补偿。两者配合以低成本实现非实时最终一致性。

#
★★

30. 冲突可串行化(Conflict Serializable)的判定,优先图(Precedence Graph)的环检测?

请说明冲突可串行化的判定,包括优先图(Precedence Graph)的环检测?

  • 冲突操作定义。
  • 优先图:节点是事务,边表示冲突依赖。
  • 无环则冲突可串行化。

冲突可串行化(conflict serializable)的判定通过优先图(precedence graph,又称冲突图)。构造:节点是每个事务;若事务 Ti 与 Tj 有冲突操作(读写同一数据、至少一个写),且 Ti 的操作先于 Tj,则加边 Ti→Tj。判定:若图中存在环(cycle),则该调度不是冲突可串行化;若无环,则冲突可串行化(等价于某串行调度),且拓扑排序给出等价的串行顺序。冲突可串行化是保证正确性的充分条件。2PL 保证冲突图无环,从而冲突可串行化。环检测是并发控制正确性验证的核心。

优先图节点是事务、边是冲突依赖;无环则冲突可串行化。2PL 保证无环。这是事务可串行化的判定方法。

#
★★

31. idle_in_transaction_session_timeout 的设置?

请说明 PostgreSQL 中 idle_in_transaction_session_timeout 的设置与作用?

  • 该参数控制空闲事务超时。
  • 超时后终止空闲事务。
  • 防止长事务污染。

idle_in_transaction_session_timeout 是 PostgreSQL 参数,设置"空闲事务"(idle in transaction,即事务已开启但长时间无操作的会话)的允许时长。若一个事务在事务中空闲超过该时长,PostgreSQL 会自动终止该会话(报错),回滚事务,从而防止空闲事务长期占用资源(持锁、阻塞 VACUUM、版本膨胀)。默认无限(0),DBA 建议设置合理值(如 60s)防止连接池/客户端异常导致的空闲事务。它只针对"事务内的空闲"(idle in transaction),不针对"事务外的空闲连接"(idle)。设置后能自动清理长事务,是运维的重要参数。合理设置可减少长事务引发的版本膨胀与锁问题。

idle_in_transaction_session_timeout 自动终止超时空闲事务,防止长事务。是治理空闲长事务的关键参数。

SET idle_in_transaction_session_timeout = 60000;  -- 60 秒
ALTER SYSTEM SET idle_in_transaction_session_timeout = 60000;
#
★★

32. SAVEPOINT 的嵌套与释放规则?

请说明 SAVEPOINT 的嵌套与释放规则?

  • SAVEPOINT 可嵌套设置。
  • 回滚到外层保存点会释放内层保存点。
  • RELEASE 释放保存点。

SAVEPOINT 支持嵌套:事务内可设置多个保存点,内层保存点在外层保存点之后。回滚规则:ROLLBACK TO SAVEPOINT sp 会回滚到 sp,并释放(删除)sp 之后定义的所有保存点(内层保存点被隐式释放);RELEASE SAVEPOINT sp 只释放 sp 及其后的保存点(不撤销操作)。因此嵌套保存点中,回滚到较外层会清除内层保存点。释放规则:RELEASE 显式释放,ROLLBACK TO 隐式释放后续保存点。理解嵌套与释放规则对复杂事务的部分回滚管理重要。

SAVEPOINT 可嵌套,回滚到外层会释放内层保存点,RELEASE 显式释放。理解嵌套与释放规则是事务部分回滚的关键。

#
★★

33. DDL 与事务的关系,PostgreSQL 支持事务性 DDL 而 MySQL 隐式提交,这种差异对迁移脚本与回滚策略有什么影响?

请说明 PostgreSQL 事务性 DDL 与 MySQL 隐式提交对迁移脚本与回滚策略的影响?

  • PostgreSQL DDL 可回滚,迁移脚本原子。
  • MySQL DDL 不可回滚,迁移需谨慎。
  • 回滚策略差异。

PostgreSQL 支持事务性 DDL,DDL 与 DML 同事务可回滚,因此迁移脚本可写在一个事务中,出错整体回滚(包括已执行的 DDL),回滚策略简单、安全。MySQL 的 DDL 隐式提交,DDL 不可回滚,且执行前自动提交当前事务,因此迁移脚本中 DDL 出错无法回滚,且 DDL 会打断事务。回滚策略差异:PostgreSQL 迁移可整体回滚;MySQL 迁移需谨慎设计——DDL 前显式提交(避免误提交),DDL 分批执行(减少阻塞),出错时需手动反向 DDL(如 DROP 刚建的表)补偿,无自动回滚。因此 MySQL 迁移需更谨慎,依赖补偿脚本而非事务回滚。理解差异对安全迁移至关重要。

PostgreSQL 迁移可事务回滚,MySQL 迁移需补偿脚本。差异源于 DDL 是否可回滚,影响迁移安全策略。

#
★★

34. MySQL DDL 的隐式提交?

请说明 MySQL DDL 的隐式提交机制?

  • 执行 DDL 前自动提交当前事务。
  • DDL 不可回滚。
  • 影响事务原子性。

MySQL 的 DDL 隐式提交:执行 DDL 语句(CREATE、ALTER、DROP、TRUNCATE、RENAME 等)前,MySQL 会自动提交当前所有未提交的事务,然后执行 DDL,DDL 本身不可回滚。这意味着:事务中执行 DDL 会强制提交之前修改,破坏原子性;DDL 出错无法回滚。TRUNCATE 也触发隐式提交(且不可回滚)。隐式提交的后果:多语句事务中混入 DDL 会意外提交;DDL 部分失败无法恢复。因此事务中应避免 DDL,或 DDL 单独执行。理解 MySQL DDL 隐式提交是正确管理事务与迁移的关键。

MySQL DDL 隐式提交当前事务且 DDL 不可回滚。事务中混入 DDL 会破坏原子性。

#
★★

35. MySQL autocommit?

请说明 MySQL autocommit 参数的作用?

  • autocommit 开启时每条语句自动提交。
  • 关闭时需显式 COMMIT。
  • 影响事务边界。

MySQL 的 autocommit 参数控制隐式提交:autocommit=ON(默认)时,每条 SQL 语句自动提交,无需显式 COMMIT,单条语句即一个事务;autocommit=OFF 时,需要显式 COMMIT 才提交,否则修改直到会话结束(未提交则回滚)。autocommit=ON 时,若要执行多语句事务,需显式 BEGIN/START TRANSACTION 开启事务,事务内语句不自动提交,直到 COMMIT/ROLLBACK。autocommit 影响事务边界:ON 时单语句自动提交,适合简单操作;OFF 时需显式提交,适合批量操作。误用 autocommit=ON 做多语句操作会破坏原子性。理解 autocommit 是事务管理的基础。

autocommit=ON 每条语句自动提交,OFF 需显式 COMMIT。多语句事务需显式 BEGIN。理解其影响事务边界。

#
★★

36. RELEASE SAVEPOINT?

请说明 RELEASE SAVEPOINT 的语法与语义?

  • RELEASE SAVEPOINT 释放保存点。
  • 释放后保存点不可用。
  • 已执行的操作保留。

RELEASE SAVEPOINT sp 释放指定的保存点 sp。释放后,该保存点及其之后定义的所有保存点被删除,后续无法再 ROLLBACK TO SAVEPOINT sp(会报错)。但释放保存点不会撤销已执行的操作(与 ROLLBACK TO 不同,RELEASE 只删除标记,不回滚数据)。RELEASE 用于清理不再需要的保存点,减少保存点管理开销。释放后事务继续,可最终 COMMIT。理解 RELEASE 与 ROLLBACK TO 的区别:RELEASE 只删除保存点不撤销操作,ROLLBACK TO 撤销到保存点的操作。正确使用 RELEASE 管理保存点生命周期。

RELEASE 只删除保存点标记,不撤销操作;ROLLBACK TO 撤销操作。释放后保存点不可用。

#
★★

37. 乐观并发控制(OCC)的冲突检测与重试策略(版本号/条件更新)在业务中的应用

请说明乐观并发控制(OCC)的冲突检测与重试策略,包括版本号/条件更新在业务中的应用?

  • OCC 无锁,提交时校验冲突。
  • 版本号/条件更新检测冲突。
  • 冲突时重试。

乐观并发控制(OCC)不提前加锁,操作基本可并发执行,提交时校验是否冲突。冲突检测的常见实现:版本号(version field)——每次更新 SET version = version + 1 WHERE id = ? AND version = ?,若影响行数为 0 说明版本不符(被其他事务修改),冲突;条件更新(CAS)——更新时带旧值条件,WHERE balance = ?,影响行数为 0 说明值已变。业务应用:乐观锁(如库存扣减 UPDATE stock SET num = num - 1 WHERE id = ? AND num > 0)、版本号更新(如 UPDATE ... WHERE version = 旧版本)。冲突时重试:捕获冲突(影响行数为 0),重新读取最新数据,重新计算并重试,直至成功。OCC 适合读多写少、冲突少的场景,避免锁开销,但冲突多时重试频繁。条件更新与版本号是 OCC 在业务中的常用实现。

OCC 提交时校验,用版本号/条件更新检测冲突,冲突时重试。适合冲突少的场景,避免锁开销。

UPDATE account SET balance = balance - 100, version = version + 1
WHERE id = 1 AND version = 5;  -- 影响行数为 0 则冲突,重试
#

38. PostgreSQL 的 statement_timeout/lock_timeout/idle_in_transaction_session_timeout 的区别与应用

请说明 PostgreSQL 的 statement_timeout、lock_timeout、idle_in_transaction_session_timeout 的区别与应用?

  • statement_timeout:单语句执行超时。
  • lock_timeout:等待锁超时。
  • idle_in_transaction_session_timeout:事务内空闲超时。

PostgreSQL 三个超时参数:statement_timeout 限制单条语句执行的最大时间,超时中止语句(如慢查询);lock_timeout 限制语句等待锁的最长时间,超时中止等待锁的语句(避免无限等待锁);idle_in_transaction_session_timeout 限制事务内"空闲"(无操作)的时长,超时终止会话(清理空闲长事务)。三者应用场景:statement_timeout 防慢查询拖垮;lock_timeout 防锁等待死锁/无限阻塞;idle_in_transaction_session_timeout 防空闲长事务。设置时需权衡:过小会误杀正常慢查询/锁等待,过小也影响。合理设置这三个超时能提升数据库稳定性。它们从不同维度(执行时间、锁等待、事务空闲)约束会话。

三个超时分别约束语句执行、锁等待、事务空闲。是 PostgreSQL 运维与防故障的关键参数。