Ver Fonte

提交使用说明

yuhongqi há 6 dias atrás
pai
commit
229d16011a

+ 280 - 0
fs-service/src/main/resources/db/changelog/Liquibase-changelog使用说明.md

@@ -0,0 +1,280 @@
+# Liquibase Changelog 使用说明
+
+> 适用模块:`fs-service`(所有依赖它的启动模块启动时自动执行)  
+> 配置入口:`fs-service/src/main/resources/application-common.yml` → `fs.liquibase.*`
+
+---
+
+## 1. 目录结构
+
+```
+db/changelog/
+├── db.changelog-master.xml          ← 主入口(唯一入口,必须用 XML)
+├── baseline/
+│   ├── init-meta.sql                ← 创建 MD5 元数据表
+│   └── baseline.sql                 ← 基线标记(不改表结构)
+├── changes/
+│   └── 20260613-live-user-add-is-del.sql   ← 业务 DDL 变更
+└── draft/                           ← 草稿目录,不会被 master 引用,启动不执行
+    └── 20260615-live-user-drop-is-del.sql
+```
+
+| 目录/文件 | 作用 |
+|-----------|------|
+| `db.changelog-master.xml` | 按顺序 `include` 子 changelog,Liquibase 只认这一份入口 |
+| `baseline/` | 首次接入、元数据表、基线 tag,一般很少改 |
+| `changes/` | 日常 DDL/DML 变更,**新增 SQL 放这里** |
+| `draft/` | 未纳入 master 的草稿,不参与 MD5 门禁,不执行 |
+
+---
+
+## 2. `db.changelog-master.xml` 用法
+
+### 2.1 文件作用
+
+这是 **Liquibase 唯一主入口**。应用启动时,`LiquibaseStartupGate` 读取配置:
+
+```yaml
+fs.liquibase.changelog: db/changelog/db.changelog-master.xml
+```
+
+然后通过 XML 的 `<include>` 依次加载 SQL 子文件并执行其中的 changeset。
+
+> **注意**:SQL 格式 **不支持** `--include`。主入口必须是 XML(或 YAML),不能写成 `db.changelog-master.sql`。
+
+### 2.2 当前内容
+
+```xml
+<include file="baseline/init-meta.sql" relativeToChangelogFile="true"/>
+<include file="baseline/baseline.sql" relativeToChangelogFile="true"/>
+<include file="changes/20260613-live-user-add-is-del.sql" relativeToChangelogFile="true"/>
+```
+
+| 属性 | 说明 |
+|------|------|
+| `file` | 相对 master 文件的路径 |
+| `relativeToChangelogFile="true"` | 路径相对于 `db.changelog-master.xml` 所在目录解析 |
+
+**执行顺序 = include 的书写顺序**,上面的文件会按 1 → 2 → 3 依次执行。
+
+### 2.3 新增一条 SQL 变更的标准步骤
+
+1. 在 `changes/` 下新建文件,建议命名:`YYYYMMDD-模块-简述.sql`  
+   例:`20260620-order-add-index.sql`
+2. 在文件内写 changeset(见第 3 节格式)
+3. 在 `db.changelog-master.xml` **末尾**追加一行 include:
+
+```xml
+<include file="changes/20260620-order-add-index.sql" relativeToChangelogFile="true"/>
+```
+
+4. 本地启动应用(或 `mvn compile` 后完整重启)
+5. 查库确认:
+
+```sql
+SELECT ID, AUTHOR, EXECTYPE, DATEEXECUTED, FILENAME
+FROM DATABASECHANGELOG
+ORDER BY DATEEXECUTED DESC;
+```
+
+### 2.4 不要做的事
+
+| 错误做法 | 后果 |
+|----------|------|
+| 只改 SQL 文件名,不更新 master 里的 `file=` | Liquibase 找不到文件或仍读旧路径 |
+| 把 SQL 放在 `changes/` 但不写进 master | 文件存在但不会执行 |
+| 用 SQL 文件当 master 并写 `--include` | 解析 0 条 changeset,门禁报错 |
+| 修改 **已发布且已执行** 的 changeset 内容 | checksum 不一致,Liquibase 校验失败 |
+| 在 `draft/` 里放正式变更却不 include | 永远不会执行 |
+
+### 2.5 启动门禁简要流程
+
+```
+启动 → 读 master.xml → 解析 changeset
+     → 对比 DATABASECHANGELOG(有无未执行/缺失记录)
+     → 有 pending 则 liquibase.update()
+     → 全部写入 DATABASECHANGELOG 后同步 bundle MD5(database_init_meta 表)
+     → 失败则禁止启动(fail-fast: true)
+```
+
+MD5 参与计算的文件:`db/changelog/` 下 `sql/xml/yaml/yml`,**排除 `draft/` 目录**。
+
+---
+
+## 3. `20260613-live-user-add-is-del.sql` 字段说明
+
+该文件包含 **2 个 changeset**(一个文件可写多条,按顺序执行)。
+
+### 3.1 文件头(必须)
+
+```sql
+--liquibase formatted sql
+```
+
+声明这是 Liquibase formatted SQL。缺少此行,整个文件不会被识别。
+
+---
+
+### 3.2 Changeset 1:为 `live_user` 增加 `is_del`
+
+```sql
+--changeset yhq:20260613-live-user-add-is-del
+```
+
+| 部分 | 值 | 说明 |
+|------|-----|------|
+| **author** | `yhq` | 变更作者/工号,写入 `DATABASECHANGELOG.AUTHOR` |
+| **id** | `20260613-live-user-add-is-del` | 全局唯一标识,写入 `DATABASECHANGELOG.ID` |
+
+> 格式必须是 `author:id`,**中间有英文冒号**。  
+> 错误示例:`--changeset 20260613-live-user-add-is-del`(缺 author,会导致 0 条解析)
+
+**前置条件:**
+
+```sql
+--preconditions onFail:MARK_RAN
+--precondition-sql-check expectedResult:1 SELECT ... table_name = 'live_user'
+--precondition-sql-check expectedResult:0 SELECT ... column_name = 'is_del'
+```
+
+| 行 | 含义 |
+|----|------|
+| `onFail:MARK_RAN` | 前置不满足时不报错,标记为已执行(`EXECTYPE=MARK_RAN`),跳过 SQL |
+| `expectedResult:1` + 表存在查询 | 要求 `live_user` 表必须存在 |
+| `expectedResult:0` + 列不存在查询 | 要求 `is_del` 列尚不存在才执行 ADD |
+
+> formatted SQL 的 precondition 请用 `--precondition-sql-check`,不要用 `--precondition-column-exists` 等非 SQL 格式写法。
+
+**DDL 与字段:**
+
+```sql
+ALTER TABLE live_user
+    ADD COLUMN is_del TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除 0-未删除 1-已删除';
+```
+
+| 字段 | 类型 | 默认值 | 说明 |
+|------|------|--------|------|
+| `is_del` | `TINYINT NOT NULL` | `0` | 逻辑删除:`0` 未删除,`1` 已删除 |
+
+**回滚(可选):**
+
+```sql
+--rollback ALTER TABLE live_user DROP COLUMN is_del;
+```
+
+---
+
+### 3.3 Changeset 2:为 `fs_course_play_source_config` 增加 `integral_goods`
+
+```sql
+--changeset yhq:20260613-fs-course-play-source-config-add-integral-goods
+```
+
+| 部分 | 值 | 说明 |
+|------|-----|------|
+| **author** | `yhq` | 同上 |
+| **id** | `20260613-fs-course-play-source-config-add-integral-goods` | 与 changeset 1 同文件但 **id 必须不同** |
+
+**前置条件:**
+
+| 检查 | 说明 |
+|------|------|
+| 表 `fs_course_play_source_config` 存在 | `expectedResult:1` |
+| 列 `integral_goods` 不存在 | `expectedResult:0` |
+
+**DDL 与字段:**
+
+```sql
+ALTER TABLE fs_course_play_source_config
+    ADD COLUMN integral_goods VARCHAR(2000) NULL DEFAULT NULL COMMENT '积分商品配置';
+```
+
+| 字段 | 类型 | 默认值 | 说明 |
+|------|------|--------|------|
+| `integral_goods` | `VARCHAR(2000) NULL` | `NULL` | 积分商品配置,一般为 JSON/文本配置 |
+
+业务侧(如 `WxMaConfiguration`)启动时会查询该列,**必须先通过 Liquibase 执行本 changeset**。
+
+**回滚:**
+
+```sql
+--rollback ALTER TABLE fs_course_play_source_config DROP COLUMN integral_goods;
+```
+
+---
+
+## 4. 新增 changeset 模板(复制使用)
+
+```sql
+--liquibase formatted sql
+
+--changeset yhq:YYYYMMDD-简述
+--preconditions onFail:MARK_RAN
+--precondition-sql-check expectedResult:1 SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = '你的表名'
+--precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = '你的表名' AND column_name = '你的列名'
+ALTER TABLE 你的表名 ADD COLUMN 你的列名 ...;
+--rollback ALTER TABLE 你的表名 DROP COLUMN 你的列名;
+```
+
+然后在 `db.changelog-master.xml` 追加:
+
+```xml
+<include file="changes/你的文件名.sql" relativeToChangelogFile="true"/>
+```
+
+---
+
+## 5. 常见问题
+
+### Q1:启动报「未解析到任何 changeset」
+
+- master 是否用 **XML** 且 include 路径正确
+- SQL 是否有 `--liquibase formatted sql`
+- `--changeset` 是否为 **`author:id`** 格式
+
+### Q2:`DATABASECHANGELOG` 没有记录但表结构变了
+
+- 不要手工改表后指望 Liquibase 补记录;应走 changeset 或 `changelogSync`(需 DBA/负责人评估)
+- 以前若存在绕过 Liquibase 的补 DDL 逻辑,不会写 `DATABASECHANGELOG`
+
+### Q3:changeset 已执行,能否改 SQL 内容?
+
+- **不能**改已执行 changeset 的 SQL 正文
+- 需要新变更时 **新建文件 + 新 id**,在 master 追加 include
+
+### Q4:draft 目录里的 SQL 什么时候生效?
+
+1. 移到 `changes/`(或 `baseline/`)
+2. 在 `db.changelog-master.xml` 增加 `<include>`
+3. 重新编译并完整重启
+
+---
+
+## 6. 相关配置速查
+
+```yaml
+fs:
+  liquibase:
+    enabled: true
+    fail-fast: true
+    changelog: db/changelog/db.changelog-master.xml
+    changelog-root: classpath:db/changelog/
+    meta-table: database_init_meta
+```
+
+| 配置项 | 说明 |
+|--------|------|
+| `changelog` | master 入口 classpath 路径 |
+| `meta-table` | 存 bundle MD5 的表,与 `baseline/init-meta.sql` 创建的表名一致 |
+| `fail-fast` | 迁移/校验失败是否禁止启动 |
+
+---
+
+## 7. 验证清单(发版前)
+
+- [ ] 新 SQL 已加入 `db.changelog-master.xml`
+- [ ] 每个 changeset 为 `author:id` 格式且 id 全局唯一
+- [ ] precondition 使用 `--precondition-sql-check`
+- [ ] 本地启动日志:`已解析=N, 待执行=0, 缺失记录=0`
+- [ ] `DATABASECHANGELOG` 有新记录
+- [ ] 业务依赖的新列/索引在库中真实存在