数据库迁移工具与反应式关系型访问(R2DBC 与 Hibernate Reactive)

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

1. Flyway 与 Spring Boot 的集成(spring-boot-starter-jdbc + flyway-core)

请说明 Flyway 与 Spring Boot 的集成方式(spring-boot-starter-jdbc + flyway-core)?

  • Flyway 依赖与自动配置
  • 迁移脚本位置
  • 启动时执行

Flyway 与 Spring Boot 集成:引入 flyway-core(与 spring-boot-starter-jdbc 一起),Spring Boot 自动配置 Flyway,在应用启动时自动执行迁移脚本。默认迁移脚本位于 classpath:db/migration(可通过 spring.flyway.locations 配置),命名规范为 V1__描述.sql、V2__描述.sql 等。Flyway 在启动时检查 schema 版本,执行未应用的迁移并记录到 schema history 表。Spring Boot 提供 spring.flyway 配置项(enabled、locations、baselineOnMigrate 等)。集成后数据库结构随应用启动自动迁移。

Spring Boot 自动配置 Flyway 使其在启动时迁移。理解依赖、脚本位置与命名规范,可顺利集成数据库迁移。

#
★★★

2. Flyway 在 Spring Boot 4.x 的兼容性

请说明 Flyway 在 Spring Boot 4.x 的兼容性?

  • 版本兼容性
  • API 变更
  • 升级注意事项

Flyway 在 Spring Boot 4.x 的兼容性需匹配 Flyway 支持的版本。Spring Boot 4.x 升级到新的 Spring Framework/Jakarta,可能影响 Flyway 的自动配置与依赖。Flyway 的 API 版本(如 Flyway 10/11)与 Spring Boot 4.x 的自动配置适配需一致,否则启动失败或迁移异常。升级时注意:Flyway 版本与 Spring Boot 管理的依赖版本对齐、flyway-database 等模块、以及 Flyway 的配置项变化。使用与 Spring Boot 4.x 匹配的 Flyway 版本,确保兼容。

框架主版本升级需同步 Flyway 版本。理解版本对齐与依赖,可避免兼容性问题。

#
★★★

3. Flyway 的 baseline 与 repair 命令

请说明 Flyway 的 baseline 与 repair 命令?

  • baseline 的作用
  • repair 的作用
  • 使用场景

Flyway 的 baseline 用于对已有数据库建立基线:在数据库已有 schema 但无迁移历史时,baseline 将当前状态标记为基线版本,之后 Flyway 从该版本之后开始迁移,避免重复执行已有结构。repair 用于修复 schema history 表与迁移脚本的不一致:删除失败的迁移记录、纠正 checksum 错误、重新对齐版本。场景:baseline 用于"从已有数据库接管";repair 用于迁移失败后清理脏状态或修复 checksum 被修改导致的校验失败。两者是 Flyway 运维的常用命令。

baseline 建立基线从已有库接管,repair 修复历史不一致。理解其作用,可安全处理迁移接管与失败修复。

#
★★★

4. Flyway 的 schema history 表如何在多实例并发启动时通过表锁保证迁移互斥,锁等待与超时失败如何处理

请说明 Flyway 的 schema history 表如何在多实例并发启动时通过表锁保证迁移互斥,以及锁等待与超时失败的处理?

  • schema history 表
  • 表锁互斥
  • 锁等待与超时

Flyway 使用 schema history 表(默认 flyway_schema_history)记录迁移版本。多实例并发启动时,Flyway 会先获取该表的锁(数据库锁,如 MySQL 的表锁或 advisory lock、Oracle 的锁),保证同一时间只有一个实例执行迁移,其他实例等待。获得锁的实例执行迁移并更新历史,完成后释放锁,其他实例获取锁后检测到迁移已完成则跳过。锁等待与超时:若某实例获取锁失败或等待超时(数据库锁等待超时),Flyway 会抛异常导致启动失败;处理上可配置等待重试或记录日志,超时后需检查是否有实例卡在迁移。生产环境应避免迁移长时间持锁。

schema history 表 + 数据库锁实现多实例迁移互斥。理解锁等待与超时,可避免多实例并发迁移冲突。

#
★★★

5. Flyway/Liquibase 与 Git 版本对齐

请说明 Flyway/Liquibase 与 Git 版本对齐?

  • 迁移脚本与代码版本
  • 版本对齐
  • 协作规范

Flyway/Liquibase 与 Git 版本对齐指:数据库迁移脚本与代码版本应保持同步,避免"代码新但数据库未迁移"或"迁移脚本与代码逻辑不一致"。实践中将迁移脚本纳入版本控制,与代码一起提交、评审、发布;发布时按版本顺序执行迁移,保证代码与数据库结构匹配。Git 对齐的关键是:迁移脚本不可修改(只追加),基线与分支合并时注意版本冲突,用版本号/changeSet 唯一标识。通过 CI 流水线按版本顺序自动迁移,保证多环境一致。

迁移脚本与代码同版本管理,保证"代码-数据库"一致。理解版本对齐与不可修改原则,可避免迁移冲突。

#
★★★

6. Liquibase 的 include/includeAll 与格式化

请说明 Liquibase 的 include/includeAll 与格式化?

  • include/includeAll
  • 变更集组织
  • 格式化

Liquibase 通过 changelog 文件组织变更集,include 引入单个其他 changelog 文件,includeAll 引入目录下所有 changelog 文件。includeAll 便于按模块/目录组织变更集,但需注意加载顺序。格式化:Liquibase 支持 XML、YAML、JSON、SQL 等格式的 changelog,格式化指变更集的结构化描述(如 SQL 格式的注释规范)。格式化 SQL changelog 需遵循 Liquibase 的注释约定(--changeset author:id)。include/includeAll 结合格式化可模块化组织变更。

include/includeAll 组合 changelog 文件,格式化定义变更集。理解其组织方式,可模块化管理数据库变更。

#
★★★

7. Liquibase 的 liquibase.properties 与 profile

请说明 Liquibase 的 liquibase.properties 与 profile?

  • liquibase.properties 配置
  • 多环境 profile
  • 配置方式

liquibase.properties 是 Liquibase 的配置文件,集中配置数据源、changelog 路径、上下文、参数等。多环境(dev/staging/prod)可通过不同 profile 或 properties 文件区分,如按环境指定不同的 changeLogFile、contexts、dataSource。Liquibase 支持 contexts(运行/上下文)与 profiles 控制哪些变更集在哪个环境执行,实现环境差异。通过 properties 文件 + 环境变量/命令行参数组合,可灵活配置多环境迁移。

liquibase.properties 集中配置,profile/context 区分环境。理解其配置,可管理多环境迁移差异。

#
★★★

8. Liquibase 的 policyContext 治理

请说明 Liquibase 的 policyContext 治理?

  • policyContext 的作用
  • 变更集治理
  • 数据/安全策略

Liquibase 的 policyContext 用于在变更集上与治理策略(如数据安全、合规、审批)关联,结合 Liquibase 的 policyContext 机制对变更集进行分级管控。它允许根据变更集的上下文(如是否涉及敏感数据、生产环境)应用不同的治理策略,如要求审批、限制执行。policyContext 治理是 Liquibase 在企业级合规场景下的能力,配合 contexts 与审批流程,确保变更集在合规要求下执行。适用大规模团队与合规要求高的迁移管理。

policyContext 是 Liquibase 的治理/合规机制,按策略管控变更集。理解其用途,可满足企业级迁移治理需求。

#
★★

9. Liquibase 的 preConditions 条件执行

请说明 Liquibase 的 preConditions 条件执行?

  • preConditions 的作用
  • 条件校验
  • 使用场景

Liquibase 的 preConditions 在变更集执行前校验条件,满足条件才执行,否则跳过或报错。可校验:表是否存在、列是否存在、数据库类型、版本、运行 context 等。preConditions 用于保证变更集在正确的数据库状态下执行(如先建表再加列),避免重复执行或错误执行。通过 onFail / onError 控制失败行为(跳过、报错、标记)。它是迁移健壮性的关键,防止在意外状态下执行变更。

preConditions 保证变更前置条件满足,是迁移的安全校验。理解其条件与失败行为,可写出健壮的迁移。

#
★★

10. 一次性数据回填脚本如何保证幂等(唯一键/记录状态字段)并支持安全重跑

请说明一次性数据回填脚本如何保证幂等(唯一键/记录状态字段)并支持安全重跑?

  • 幂等性
  • 唯一键/状态字段
  • 安全重跑

一次性数据回填脚本需保证幂等,即重复执行不产生重复或错误数据。手段:1. 用唯一键约束(如业务唯一键)配合 INSERT ... ON DUPLICATE KEY 或 INSERT IGNORE,重复插入不报错;2. 用记录状态字段(如 status/processed)标记已处理记录,重跑时跳过已处理;3. 先查后插(存在则跳过)。通过这些手段,脚本可安全重跑(如迁移失败重试、部分成功再跑)。回填脚本还应分批执行、记录进度,支持断点续跑。

幂等靠唯一键/状态字段避免重复,安全重跑是运维需要。理解幂等设计,可保证数据回填可靠。

#
★★

11. Flyway 与 Liquibase 的选型对比,社区版能力、回滚模型、多数据库支持与团队协作

请说明 Flyway 与 Liquibase 的选型对比(社区版能力、回滚模型、多数据库支持与团队协作)?

  • 社区版能力
  • 回滚模型
  • 多数据库支持

Flyway 与 Liquibase 选型对比:Flyway 社区版支持 SQL 脚本迁移,简单、SQL 原生、上手快,但回滚能力有限(社区版不支持自动回滚);Liquibase 社区版支持 XML/YAML/JSON/SQL 变更集,回滚模型更完善(可定义 rollback),多数据库支持广,且变更集可用 changelog 管理。团队协作:Flyway 用版本号脚本,Liquibase 用 changeSet + author。选型:项目简单、SQL 熟练用 Flyway;需要回滚、多格式、复杂变更管理用 Liquibase。回滚模型与团队协作方式是主要差异。

两者的本质差异在回滚模型与变更集组织方式。理解选型对比,可据团队需求选择迁移工具。

#
★★

12. Liquibase 的变更集(ChangeSet)与回滚(Rollback)

请说明 Liquibase 的变更集(ChangeSet)与回滚(Rollback)?

  • ChangeSet 的定义
  • 回滚机制
  • 回滚编写

Liquibase 的 ChangeSet 是变更的最小单元,有 id + author + file 唯一标识,包含具体的数据库变更(建表、加列等)。ChangeSet 支持定义 rollback 回滚动作(如 DROP TABLE、删除列),回滚时执行定义的回滚逻辑;未定义 rollback 的 ChangeSet 在回滚时需自动/手动处理。Liquibase 通过 rollback 命令回滚到指定版本,依赖 rollback 定义与 changelog。回滚模型是 Liquibase 相对 Flyway 的优势,便于版本回退。

ChangeSet 是变更单元,rollback 定义回滚逻辑。理解回滚机制,可实现数据库版本回退。

#
★★

13. Spring 的 DatabaseClient 如何以响应式方式执行 SQL 并映射结果,fetch 之后的 map/one/all 各返回什么类型

请说明 Spring 的 DatabaseClient 如何以响应式方式执行 SQL 并映射结果,fetch 之后的 map/one/all 各返回什么类型?

  • DatabaseClient 响应式
  • fetch 的 map/one/all
  • 返回类型

Spring 的 DatabaseClient 是响应式数据库访问客户端,执行 SQL 返回 Flux/Mono。用法:databaseClient.sql(sql).bind(...).map(...).fetch().one() 或 .all()。fetch 后:one() 返回 Mono (期望单条结果,多条会报错),all() 返回 Flux (多条结果),first() 返回 Mono(取第一条)。map 用于将结果行映射为对象(可指定 RowMapper 或 Bean 映射)。返回类型为响应式:one 返回 Mono,all 返回 Flux,具备响应式流语义(订阅、背压)。

DatabaseClient 的 map/fetch 提供响应式结果映射,one/all 决定 Mono/Flux。理解返回类型,可正确编写响应式数据访问。

#
★★

14. 反应式事务中连接是如何在 Context 中绑定并沿订阅链传递的,与传统 ThreadLocal 绑定连接的机制有何不同

请说明反应式事务中连接是如何在 Context 中绑定并沿订阅链传递的,与传统 ThreadLocal 绑定连接的机制有何不同?

  • 反应式 Context 绑定连接
  • 订阅链传递
  • 与 ThreadLocal 的不同

反应式事务中,连接不是绑定到线程(ThreadLocal),而是绑定到响应式 Context(Reactor Context),沿订阅链向下传递。获取连接时,连接被放入 Context,后续操作从 Context 读取该连接,从而保证同一事务内的操作共享同一连接。这与传统 ThreadLocal 绑定连接的机制根本不同:ThreadLocal 绑定线程(线程切换即丢失),Context 绑定订阅链(不依赖线程,线程切换不影响)。反应式因此可在不同线程间流转而保持连接归属。事务通过 TransactionalOperator 在 Context 中管理连接与事务。

反应式用 Context 沿订阅链传递连接,ThreadLocal 绑定线程。理解其差异,可正确设计反应式事务。

#
★★

15. 反应式链路中 @Transactional 为何失效,TransactionalOperator.transactional 如何把多个操作绑定到同一连接与事务

请说明反应式链路中 @Transactional 为何失效,TransactionalOperator.transactional 如何把多个操作绑定到同一连接与事务?

  • @Transactional 在反应式中的失效
  • TransactionalOperator
  • 绑定同一连接与事务

在反应式链路中,@Transactional 声明式事务失效,因为它是基于 ThreadLocal 的同步事务代理,而反应式操作不绑定线程、跨越线程执行,ThreadLocal 无法沿订阅链传递,事务上下文丢失。正确做法是用 TransactionalOperator(编程式反应式事务):transactionalOperator.transactional(mono) 将操作包进反应式事务,操作在订阅时从 Context 绑定连接与事务,同一 TransactionalOperator 包装的多个操作共享同一连接与事务边界(提交/回滚)。通过 Context 传播连接,替代 ThreadLocal 实现反应式事务。

@Transactional 依赖 ThreadLocal,反应式无线程绑定故失效。TransactionalOperator 用 Context 实现反应式事务。理解其差异,可正确编写反应式事务。

#
★★

16. 多个应用副本同时执行 Flyway migrate 时,如何避免重复执行与版本错乱,baseline 与 lock 机制各起什么作用

请说明多个应用副本同时执行 Flyway migrate 时,如何避免重复执行与版本错乱,baseline 与 lock 机制各起什么作用?

  • 多副本并发迁移
  • 锁机制
  • baseline 的作用

多个应用副本同时执行 Flyway migrate 时,Flyway 通过 schema history 表的数据库锁(表锁/advisory lock)保证同一时间只有一个副本执行迁移,其他副本等待,避免重复执行与版本错乱。获得锁的副本执行迁移并更新历史,其余副本检测到版本已应用则跳过。baseline 用于用已有数据库接管时建立基线,标记已存在的结构,避免从已有库重复执行迁移。两者作用:lock 保证并发互斥,baseline 处理已有库接管,共同保证迁移的一致性与版本正确。

lock 解决并发互斥,baseline 解决已有库接管。理解二者,可安全处理多副本与既有数据库。

#
★★

17. 大表 DDL 在线变更(gh-ost/pt-osc)如何与 Flyway/Liquibase 协作,影子表切换期间迁移脚本的版本一致性如何保证

请说明大表 DDL 在线变更(gh-ost/pt-osc)如何与 Flyway/Liquibase 协作,影子表切换期间迁移脚本的版本一致性如何保证?

  • 在线 DDL 变更
  • 影子表切换
  • 版本一致性

大表 DDL 在线变更(gh-ost、pt-osc)通过影子表 + 增量同步 + 切换的方式避免阻塞,与 Flyway/Liquibase 协作时,将在线变更作为迁移脚本的一部分(或单独流程),但需保证迁移脚本的版本一致性。影子表切换期间,应用的迁移脚本记录仍需与最终表结构一致:切换完成后,迁移脚本应反映最终结构,且避免在切换期间执行其他依赖该表的迁移。版本一致性保证:迁移脚本按版本顺序执行,切换操作幂等且可校验最终结构,schema history 记录切换完成状态,避免切换前/后进行冲突的 DDL。

在线 DDL 与迁移工具协作需协调版本与切换,保证最终结构一致。理解影子表切换与版本记录,可安全进行大表变更。

#
★★

18. Flyway Teams 与社区版的差异

请说明 Flyway Teams 与社区版的差异?

  • 社区版能力
  • Teams 特有功能
  • 选型

Flyway 社区版免费,提供基础的 SQL 迁移、版本管理、校验、多数据库支持。Flyway Teams(付费)增加企业级功能:回滚(undo)、数据迁移(repeatable 增强)、环境/team 协作、权限管理、支持更多数据库方言、Oracle/PostgreSQL 高级功能、审计与 RBAC 等。社区版适合个人/中小项目,Teams 适合需要回滚、企业治理、多环境协作的团队。选型:简单迁移用社区版,需要回滚与治理能力用 Teams。

Teams 相对社区版的核心差异是回滚与企业治理功能。理解差异,可据需求选择 Flyway 版本。

#
★★

19. Flyway 的 repeatable migrations 与占位符

请说明 Flyway 的 repeatable migrations 与占位符?

  • repeatable 迁移
  • 占位符
  • 使用场景

Flyway 的 repeatable migrations(R__ 前缀)是可重复执行的迁移,每次内容变化(checksum 变化)时重新执行,适合视图、存储过程、函数等可重复定义的对象。占位符(placeholder)是 Flyway 支持在 SQL 中定义的可替换变量(如 ${schema}),迁移时按配置替换,用于环境差异(不同 schema 名、前缀)。repeatable 迁移 + 占位符可维护可重复对象与环境差异。repeatable 迁移不以版本号唯一,而是以 checksum 判断是否重新执行。

repeatable 迁移用于可重复对象,占位符用于环境差异。理解其机制,可管理视图/存储过程与环境配置。

#
★★

20. Flyway 的 validateOnMigrate 与失败处理

请说明 Flyway 的 validateOnMigrate 与失败处理?

  • validateOnMigrate
  • 校验失败
  • 失败处理

validateOnMigrate 控制 Flyway 在迁移前是否校验已应用迁移的 checksum 与 schema history 的一致性。若开启且发现已应用迁移的 SQL 被修改(checksum 不匹配)或历史不一致,则校验失败,迁移中止。失败处理:校验失败需用 repair 修复(更新 checksum 记录)或确认迁移是否被非法修改。validateOnMigrate 保证迁移脚本不可变性与历史一致性,防止已应用迁移被篡改。生产建议开启以校验一致性。

validateOnMigrate 校验迁移脚本一致性,失败需 repair。理解校验机制,可保证迁移历史可信。

#
★★

21. Flyway 的迁移机制(版本、校验、执行)

请说明 Flyway 的迁移机制(版本、校验、执行)?

  • 版本管理
  • 校验
  • 执行流程

Flyway 的迁移机制:版本管理——迁移脚本按版本号(V1、V2...)排序,schema history 表记录已应用版本;校验——执行前校验已应用迁移的 checksum 与历史一致性(validateOnMigrate);执行——逐版本执行未应用的迁移,记录到 history,成功则标记,失败则中止并记录。迁移不可修改(追加新版本),保证可追溯。流程:检查 schema history → 校验 → 执行未应用迁移 → 更新 history。迁移失败时,Flyway 记录失败状态,修复后继续。

Flyway 的核心是"版本 + 校验 + 执行"的迁移流程。理解其机制,可正确使用与管理迁移。

#
★★

22. R2DBC 与 JDBC 在编程模型上的根本差异是什么,为什么 R2DBC 规范刻意不提供阻塞式 API

请说明 R2DBC 与 JDBC 在编程模型上的根本差异,以及为什么 R2DBC 规范刻意不提供阻塞式 API?

  • 阻塞 vs 响应式
  • R2DBC 的响应式 API
  • 不提供阻塞 API 的原因

R2DBC 与 JDBC 的根本差异:JDBC 是阻塞式(阻塞 I/O,调用 execute 时线程等待),R2DBC 是响应式(非阻塞,返回 Publisher/Flux/Mono,通过背压与回调驱动)。R2DBC 刻意不提供阻塞式 API,是为了保证响应式编程模型的纯粹性:一旦提供阻塞 API,调用者可能误用阻塞导致线程阻塞,破坏非阻塞链路的保证(如 WebFlux 事件循环线程)。非阻塞模型要求全链路无阻塞,因此 R2DBC 只提供响应式 API,强制保持非阻塞。这也使 R2DBC 更适合高并发 IO 密集场景。

阻塞与非阻塞是根本差异,R2DBC 不提供阻塞 API 是为保持非阻塞链路的完整性。理解其设计,可正确使用响应式数据访问。

#
★★

23. R2DBC 的 ConnectionPool(r2dbc-pool)配置模型与 HikariCP 有哪些关键差异,acquire 超时与连接校验如何设置

请说明 R2DBC 的 ConnectionPool(r2dbc-pool)配置模型与 HikariCP 的关键差异,以及 acquire 超时与连接校验的设置?

  • r2dbc-pool 配置模型
  • 与 HikariCP 差异
  • acquire 超时与校验

R2DBC 的 ConnectionPool(r2dbc-pool)配置模型与 HikariCP 关键差异:r2dbc-pool 是响应式连接池,用 ConnectionPoolConfiguration 配置(maxSize、initialSize、maxIdleTime、maxAcquireTime、maxCreateConnectionTime、maxLifeTime 等),获取连接是响应式的(返回 Mono);HikariCP 是阻塞式。acquire 超时用 maxAcquireTime 设置(获取连接等待超时),连接校验用 maxCreateConnectionTime / 连接 factory 的校验(R2DBC 无 JDBC 的 isValid/connectionTestQuery,校验通过连接创建/复用机制)。差异:r2dbc-pool 面向响应式、配置项名不同、无 JDBC 校验查询。

r2dbc-pool 是响应式连接池,配置与校验方式与 HikariCP 不同。理解其配置模型,可正确配置响应式连接池。

#
★★

24. Spring Data R2DBC 的 Repository 抽象相比 JDBC 版缺少哪些能力(如分页派生查询、懒加载),原因是什么

请说明 Spring Data R2DBC 的 Repository 抽象相比 JDBC 版缺少哪些能力(如分页派生查询、懒加载),原因是什么?

  • R2DBC Repository 能力
  • 缺少的能力
  • 原因

Spring Data R2DBC 的 Repository 相比 JDBC 版(Spring Data JPA)缺少的能力:懒加载(Lazy Loading)、实体级联、复杂关联映射、即时/延迟的关联加载、基于查询的复杂分页(R2DBC 支持有限的分页)、多对多/一对多的自动映射等。原因:R2DBC 是响应式关系型访问,无 ORM 的持久化上下文与延迟加载代理(响应式无法阻塞式动态加载关联),且 R2DBC 定位轻量、SQL 驱动,不提供 JPA 式实体管理。R2DBC Repository 更贴近 SQL 映射,关联需手动查询或投影。

R2DBC 缺 JPA 式实体管理与懒加载,因为响应式模型与 SQL 驱动。理解差异,可正确使用 R2DBC Repository。

#
★★

25. 在 WebFlux + R2DBC 链路中混入一次阻塞 JDBC 调用会破坏哪些保证,如何用 boundedElastic 隔离遗留代码

请说明在 WebFlux + R2DBC 链路中混入一次阻塞 JDBC 调用会破坏哪些保证,如何用 boundedElastic 隔离遗留代码?

  • 阻塞调用破坏的保证
  • WebFlux 线程模型
  • boundedElastic 隔离

在 WebFlux + R2DBC 链路中混入阻塞 JDBC 调用,会阻塞事件循环线程(Netty 线程),破坏非阻塞保证:阻塞事件循环线程导致其他请求无法被处理(吞吐骤降)、背压失效、以及非阻塞链路的实时性。为隔离遗留阻塞代码,应使用 boundedElastic 调度器(Reactor 的 Schedulers.boundedElastic())将阻塞调用放到独立的弹性线程池执行,避免阻塞事件循环线程。通过 subscribeOn / publishOn 切换调度器,隔离阻塞 JDBC,保持其余链路的非阻塞。boundedElastic 有线程上限,能控制阻塞线程数。

阻塞调用破坏非阻塞链路,boundedElastic 隔离阻塞线程。理解线程模型与隔离,可安全混入遗留阻塞代码。

#
★★

26. 数据库迁移与 CI 流水线集成

请说明数据库迁移与 CI 流水线的集成?

  • CI 中的迁移执行
  • 环境模拟
  • 校验与发布

数据库迁移与 CI 流水线集成:在 CI 的测试/集成阶段执行迁移脚本(Flyway/Liquibase),创建测试数据库结构,保证测试环境与生产一致;在流水线中校验迁移脚本(如 validateOnMigrate、preConditions)、检查版本冲突、按环境执行迁移。集成方式:CI 中通过 maven/gradle 插件或命令行执行迁移,测试环境用干净库跑迁移验证脚本正确性,生产发布时由部署流程执行迁移。通过 CI 集成可在发布前发现迁移脚本问题。

CI 集成迁移可提前验证脚本、保证环境一致性。理解流水线集成,可安全发布数据库变更。

#
★★

27. 数据库迁移在多租户(每租户 schema/分库)架构下的执行策略与租户感知

请说明数据库迁移在多租户(每租户 schema/分库)架构下的执行策略与租户感知?

  • 多租户迁移
  • 执行策略
  • 租户感知

多租户(每租户 schema/分库)架构下,迁移需对每个租户的 schema/分库执行,执行策略:1. 遍历所有租户执行同一套迁移脚本;2. 用租户感知的迁移工具(如 Flyway 配置按租户切换 schema,或脚本中含租户占位符);3. 新租户创建时执行基础迁移,存量租户增量迁移。需保证迁移脚本的租户无关性(用占位符/上下文指定 schema),并支持批量、并发地跨租户执行与失败重试。迁移状态需按租户记录,避免租户间遗漏。

多租户迁移需按租户执行并感知租户。理解执行策略与租户隔离,可安全地在多租户架构迁移。

#
★★

28. Hibernate Reactive 的 Mutiny 编程模型与 @WithSession/@WithTransaction 的使用边界

请说明 Hibernate Reactive 的 Mutiny 编程模型与 @WithSession/@WithTransaction 的使用边界?

  • Mutiny 编程模型
  • @WithSession/@WithTransaction
  • 使用边界

Hibernate Reactive 提供 Mutiny 编程模型(Mutiny.Session、Mutiny.StatelessSession),基于 Uni/Multi 响应式 API。@WithSession 用于在反应式方法中获取 Session(绑定到当前上下文),@WithTransaction 用于开启反应式事务(绑定事务到上下文,提交/回滚)。使用边界:@WithSession/@WithTransaction 需在反应式方法(返回 Uni/Multi)上使用,不能用于同步阻塞方法;它们通过 Mutiny 上下文传播 Session/事务,替代 @Transactional(在反应式链路失效)。适用于 WebFlux/Quarkus 等反应式栈。理解边界:反应式方法内使用,不阻塞,事务沿上下文传播。

@WithSession/@WithTransaction 是 Hibernate Reactive 的反应式事务注解,需在反应式方法使用。理解其边界,可正确编写反应式 ORM。

#

29. 数据库迁移的版本控制策略(命名规范、目录结构)

请说明数据库迁移的版本控制策略(命名规范、目录结构)?

  • 命名规范
  • 目录结构
  • 版本管理

数据库迁移的版本控制策略:命名规范——Flyway 用 V1__描述.sql(版本号 + 描述),Liquibase 用 changeSet id+author;目录结构——按环境/模块组织(如 db/migration 下按业务模块或按版本分目录),保证迁移顺序清晰。版本控制要求:迁移脚本不可修改(只追加新版本)、版本号唯一且递增、与代码版本对齐。目录结构便于管理与评审,命名规范保证可读性与顺序。多环境(dev/staging/prod)通过相同脚本 + 环境配置执行。

命名规范与目录结构保证迁移可管理、有序、可追溯。理解版本控制策略,可维护清晰的迁移体系。

#

30. 生产迁移如何设计灰度放量与回滚演练,迁移的验证指标与回滚触发条件是什么?

请说明生产迁移如何设计灰度放量与回滚演练,迁移的验证指标与回滚触发条件?

  • 灰度放量
  • 回滚演练
  • 验证指标与回滚条件

生产迁移的灰度放量:先在一部分实例/租户/流量上执行迁移,观察效果,再逐步扩大到全量,降低风险。回滚演练:在生产前演练回滚流程(用预先定义的 rollback 或基线恢复),验证回滚可行性。验证指标:迁移后的数据一致性、应用错误率、慢查询、迁移耗时、schema 校验等。回滚触发条件:迁移后出现数据错误、一致性校验失败、应用异常率上升、性能劣化等,达到阈值即触发回滚。灰度放量 + 回滚演练 + 明确指标,可安全进行生产迁移。

灰度放量控制风险,回滚演练保障可逆,指标与条件决定何时回滚。理解其设计,可安全上线迁移。

#

31. 迁移脚本在多环境(dev/staging/prod)的差异

请说明迁移脚本在多环境(dev/staging/prod)的差异?

  • 多环境迁移
  • 环境差异
  • 一致性

迁移脚本在多环境(dev/staging/prod)的差异:通常使用同一套迁移脚本保证结构一致,但环境差异通过配置(占位符、contexts、数据源)处理,而非脚本内容差异化。例如 dev 用开发库、staging 用预发布库、prod 用生产库,脚本相同,环境参数不同。差异可能包括:测试数据(dev 环境可插测试数据)、特定于环境的配置(schema 名、权限)。原则是"结构脚本一致,环境差异走配置",避免脚本漂移导致结构不一致。多环境差异通过参数化与 context 管理。

多环境迁移应保持脚本一致,差异走配置。理解一致性原则,可避免环境间结构漂移。

#

32. 迁移脚本的兼容性(向前/向后)

请说明迁移脚本的兼容性(向前/向后)?

  • 向前兼容
  • 向后兼容
  • 平滑迁移

迁移脚本的兼容性指迁移过程中新旧代码/结构兼容。向前兼容(forward):新结构可被旧代码使用(如加列时旧代码不强制用新列);向后兼容(backward):旧结构可被新代码使用(如回滚时)。设计兼容迁移:加列用可空/默认值、避免破坏性变更(删列/改类型)、分阶段迁移(先加后删)、避免旧代码访问新结构时报错。兼容性保证平滑迁移与回滚,避免迁移期间应用不可用。发布常采用"expand-contract"(先加后删)模式。

兼容性迁移允许新旧版本共存,避免破坏。理解 expand-contract 与兼容策略,可平滑迁移。

#

33. 迁移脚本的密码与密钥管理(Vault 集成)

请说明迁移脚本的密码与密钥管理(Vault 集成)?

  • 敏感信息保护
  • Vault 集成
  • 安全实践

迁移脚本中的密码与密钥(如数据源密码、脚本中的敏感值)不应硬编码,应通过密钥管理(如 HashiCorp Vault、云 KMS)管理。Vault 集成:迁移工具从 Vault 安全获取数据库连接凭据与敏感参数,脚本中不出现明文密码。安全实践:迁移脚本中避免明文敏感信息,用占位符/凭据引用,凭据由 Vault 动态注入,支持轮换与审计。迁移脚本加密存储与访问控制,防止敏感信息泄露。Vault 集成提升迁移安全性与合规性。

迁移需保护敏感信息,Vault/密钥管理安全注入。理解其集成,可避免脚本泄露凭据。

#

34. R2DBC 对批量插入、存储过程、LOB 的支持现状与限制,哪些传统 JDBC 场景目前仍难以平滑迁移

请说明 R2DBC 对批量插入、存储过程、LOB 的支持现状与限制,哪些传统 JDBC 场景难以平滑迁移?

  • R2DBC 批量插入
  • 存储过程/LOB 支持
  • 迁移限制

R2DBC 对批量插入、存储过程、LOB 的支持有限:批量插入可通过响应式批量 API 或多次执行,但缺少 JDBC 的 addBatch 批处理;存储过程支持依赖数据库驱动(部分驱动支持,语法不统一);LOB(大对象)支持依赖驱动(如 PostgreSQL 的 BYTEA 特殊处理),部分类型受限。难以平滑迁移的传统 JDBC 场景:依赖 JDBC 特定 API(如 Batch、getGeneratedKeys、特定游标/流式)、存储过程结果集、复杂多结果集、JPA 实体管理、数据库方言特殊函数等。R2DBC 生态仍较新,这些场景需评估或保留 JDBC 路径。

R2DBC 对批处理/存储过程/LOB 支持有限,某些 JDBC 场景迁移困难。理解限制,可评估迁移可行性。