# Flyway 全面引入 — 治本地/测试/正式表结构不一致根因

**日期**: 2026-05-05
**类型**: chore（基础设施引入，零业务影响）
**Release PR**: wx/HL #1686（dev → main 已合并）
**关联 PRs**: #1681 (oneshot SQL 补漏) / #1682 (pilot) / #1683 (flyway-mysql artifact 修) / #1684 (阶段 2 批量铺) / #1685 (dep 移 hl-starter-mybatis 修)
**关联工单**: #1678

## 背景

2026-05-05 一晚连续 3 次 V*.sql 测试服漏跑(PR #1659/#1661/#1668 → BadSqlGrammar 全军),根因**项目无 Flyway,DB migration 全靠运维手工跑**。Flyway 是 Java 生态最常用的 DB schema 版本管理,核心机制:

- 应用启动时自动建 `flyway_schema_history` 表,记录哪些 V*.sql 已跑
- 扫 `db/migration/` 找未跑的 V*.sql → 顺序自动 apply
- 多环境(本地/测试/正式)启动一致 → 表结构永远同步

## 改动范围

### Flyway dep 集中管理
`hl-common/hl-starter-mybatis/pom.xml` 加 `flyway-core` (Spring Boot 2.7.18 BOM 管 8.5.13) + `flyway-mysql:8.5.13` (BOM 不管,显式 version)。**4 个 DB service (user/order-v2/product-v2/resource) 全继承**(3 service 直接依赖 starter,resource-service 通过 hl-common-mybatis 间接;dep 放 starter 是因为 order-v2 不依赖 hl-common-mybatis,放后者拿不到)。

### 4 个 DB service application.yml 配 Flyway
| Service | DB schema | baseline-version |
|---|---|---|
| hl-user-service | hl_user_service | 20260505.009 |
| hl-order-service-v2 | hl_order_service_v2 | 20260505.010 |
| hl-product-service-v2 | hl_product_service | 20260418 |
| hl-resource-service | hl_resource_service | 0 (无历史 V*.sql) |

`baseline-on-migrate=true` + `validate-on-migrate=true` + `placeholder-replacement=false`。

### 不需 Flyway 的 service
- **hl-mp-service**: 无 DB(application.yml 显式 exclude DataSourceAutoConfiguration)
- **hl-gateway**: 无 DB

## 测试服验证全绿

```
user-service: history 1 行 baseline 20260505.009 / Flyway 8.5.13 / validated 7 / up to date
order-v2:     history 1 行 baseline 20260505.010 / validated 3 / up to date
product-v2:   history 1 行 baseline 20260418 / validated 1 / up to date
resource-service: history 2 行 (BASELINE 0 + V99999999.001 pilot) / validated 2 / up to date
```

## 正式环境验证全绿

dev → main release PR #1686 (24e87f6f) 合并后,prod 4 service 串行 K8s rolling deploy 全部 success,8 pod 全 1/1 ready。

```
prod /admin/wx-security/hit-log/page         → code:200 records:[] total:0
prod /admin/wx-security/blacklist/page       → code:200
prod /admin/wx-security/whitelist/page       → code:200
prod /admin/wx-security/manual-review/page   → code:200
prod /admin/wx-security/user-risk/list       → code:200 返 2 条预置规则
prod /admin/user/avatar-rejected/page        → code:200
prod /mp/review/featured                     → code:200
```

Schema 0 改动,业务全绿,Flyway 在 prod 4 schema 自动 baseline 写入元数据(只写 1 行 history,不跑任何 DDL)。

## 期间踩 2 个坑

### 坑 1: Flyway 8.x MySQL 支持拆 flyway-mysql artifact
PR #1682 pilot 启动炸 `Unsupported Database: MySQL 8.0`。Spring Boot 2.7.18 BOM 管 flyway-core 8.5.13,但**不管 flyway-mysql**。Flyway 9.x 才把 flyway-mysql 加进 Spring Boot BOM。修复 PR #1683 显式 `<version>8.5.13</version>`。

### 坑 2: dep 必须放 hl-starter-mybatis 不能放 hl-common-mybatis
PR #1684 把 Flyway dep 加 hl-common-mybatis,但 **hl-order-service-v2 只依赖 hl-starter-mybatis(没依赖 hl-common-mybatis)**,导致 order-v2 部署后 Spring Boot autoconfig 缺 flyway-core jar silently skip,Flyway 没启动。修复 PR #1685 dep 移到 hl-starter-mybatis(跟 mybatis-plus 同 starter 集中管理)。

## 后续团队铁律(已落 memory)

1. **V*.sql 合 dev 后冻结** — Flyway 严格校验 checksum,合并后改 1 个字符启动炸。要修发新 V*.sql,旧文件保留。
2. **新增 DDL 的 PR body 必列「本 PR 是否含 V*.sql 变更」**,虽然 Flyway 自动 apply,显式列出便于 review。
3. 跨 schema 反模式禁止: 一个 V*.sql 只 ALTER 本 service schema 的表(详见 cross-db-migration-module-misplaced-causes-skip.md)。

## 通知

- @mmg: 后端 schema 变更工作流升级,以后无须等运维手动跑 SQL,部署即生效
- 旧 memory P0 铁律「项目无 Flyway, V*.sql 必须手工跑」**已删除**
- 新 memory P0 铁律「V*.sql 合 dev 后冻结(Flyway checksum 严格)」**已落地**

## 历史价值

Flyway 引入是今晚一连串 BUG 反思后的根因治理。从「网关路由 404」(PR #1679) → 「SQL 漏跑 BadSqlGrammar」(PR #1681) → 「Flyway 全面引入」(PR #1682-#1685) → 「prod 自动 baseline」一气呵成,**根因彻底治理**。
