恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
数据库版本混乱?Liquibase 自动迁移 + contexts 裁剪,qkl-boot 这么管的
首页
资讯中心
/
数据库版本混乱?Liquibase 自动迁移 + contexts 裁剪,qkl-boot 这么管的
数据库版本混乱?Liquibase 自动迁移 + contexts 裁剪,qkl-boot 这么管的
发布时间:2026/10/14 1:52:49
数据库版本混乱Liquibase 自动迁移 contexts 裁剪qkl-boot 这么管的导读新同事拉代码一启动表没建、字段没加、索引没配报错信息五花八门——这种痛在多人协作项目里太常见了。qkl-boot 的做法是启动时用 Liquibase 自动建表迁移配合 LIQUIBASE_CONTEXTS 按模块和环境裁剪不用手工灌任何 SQL。先说结论数据库结构变更千万别靠谁改了谁手动执行一下 SQL这种约定。人一定会忘忘了就炸炸了还得考古 git 找哪条没执行。Liquibase 的核心思路是每个结构变更都是一个带唯一标识的 changeset数据库里记录哪些已执行启动时自动补齐没跑的。幂等、可回滚、可审计一套下来数据库变更就和代码一样有版本了。changeset 怎么写一个文件管一张表qkl-boot 的变更文件放在classpath:db/下主文件master.yaml用 includeAll 把所有分文件拉进来。每个 changeset 必须有idauthor这是它在数据库里的身份证# db/changelog/20261001-init-settlement.xmlid我习惯直接用日期序号20261001-001谁在什么时候加的git log 一对照就清楚。改已发布的 changeset 是大忌——改了内容但 id 没变Liquibase 认为它已经执行过你的修改永远不会生效还会误导后来的人。真要改就加一个新的 changeset 做补偿修改。按模块裁剪contexts 是开关qkl-boot 最实用的设计是模块裁剪demo、ai、finance、print 这些可选模块不只要在代码和 Maven Profile 层面裁剪数据库表也得跟着裁——不然关掉 ai 模块库里还躺着 ai 的表没意义。Liquibase 的context就是干这个的# db/changelog/20261002-init-ai.xmlAI 模块专用启动时通过环境变量/配置指定激活哪些 context多个用逗号分隔# 只跑基础 finance 模块的表LIQUIBASE_CONTEXTSbase,finance mvn-plqkl-bootstrap-amspring-boot:run# 全量本地开发常用LIQUIBASE_CONTEXTSbase,ai,finance,print,channel,notify mvn-plqkl-bootstrap-amspring-boot:run# application.ymlspring:liquibase:enabled:truechange-log:classpath:db/master.yamlcontexts:${LIQUIBASE_CONTEXTS:base}# 默认只跑基础模块default-schema:qkl_boot配合 Maven Profile 一起用-Pno-ai时配置里不带aicontextAI 模块的表就不建。代码、依赖、表结构三层一起裁才是真正干净的模块化。踩坑实录启动直接报 “Table already exists”现象在已跑过老版本的库上直接升级到新代码启动报错liquibase.exception.ValidationFailedException: Validation Failed: 1 changesets check failed changeSet classpath:db/master.yaml::20260901-003::qkl Reason: liquibase.exception.DatabaseException: Table sys_user already exists排查过程先查DATABASECHANGELOG表——这是 Liquibase 自己的记录表看 20260901-003 到底执行过没有。结果发现库里sys_user表是老同事手工建的SHOW CREATE TABLE的时间戳和字段都对得上但DATABASECHANGELOG里根本没有这条记录。也就是说表存在但 Liquibase 不认账启动时想再建一遍直接撞车。定位思路这是历史遗留手工 SQL 新上 Liquibase的典型冲突。Liquibase 只认自己的变更记录库里的表是黑户。直接删表重来不现实有数据改 changeset 的 id 也不对治标不治本还会污染变更历史。最终解决把手工建的表补录成已执行状态——用changelogSync让 Liquibase 把现有 changeset 标记为已应用不真正执行 SQL# 只标记不执行把当前变更文件里的 changeset 全部记入 DATABASECHANGELOGmvn liquibase:changelogSync\-Dliquibase.changeLogFiledb/master.yaml\-Dliquibase.defaultSchemaNameqkl_boot跑完再启动Liquibase 认为所有 changeset 已执行跳过建表正常进入后续迁移。一次性操作别在正常流程里用——它会把所有变更都标记为已执行新加的 changeset 也会被跳过。生产补丁怎么打新增 changeset别改旧的上线后要加个索引很多人的第一反应是打开之前的 changeset 把 createIndex 塞进去。千万别——那条 changeset 已经在生产执行过了Liquibase 不会重跑你的索引永远不会建出来而且别人 review 变更记录时还以为索引早就有了排查慢查询时白折腾半天。正确的姿势永远是新增# 生产环境只应用这一个补丁--tag 是可选的安全标记mvn liquibase:update\-Dliquibase.changeLogFiledb/master.yaml\-Dliquibase.defaultSchemaNameqkl_boot\-Dliquibase.contextsbase跑完SELECT * FROM DATABASECHANGELOG ORDER BY DATEEXECUTED DESC LIMIT 5;确认新 changeset 已记录。这个习惯养成了生产变更就有了完整的审计链——哪天出问题谁加的、什么时候加的、加的什么一条 SQL 查清楚。还有几个容易踩的点多个开发分支并行时 changeset 冲突。两个人都在 20261013 加了 changesetid 撞了后 merge 的人启动就报 duplicate。约定id 里带上自己名字缩写或 JIRA 号比如20261013-qkl-001从根上避免撞车。线上变更用--changelogFile打补丁别改已发布 changeset。生产环境加索引、加字段一律新增 changeset不要回头编辑旧的。非 SQL 变更类型要小心。sqlFile类型执行任意 SQL在 Oracle/MySQL 方言差异下容易翻车能用 createTable/addColumn 等原生标签就用原生标签跨库兼容性更好。可以直接抄的结论每个结构变更是带唯一 id 的 changesetid用日期作者序号已发布的 changeset 永不修改master.yamlincludeAll 管总入口按模块加context配合LIQUIBASE_CONTEXTS裁剪表结构老库升级用changelogSync把手工 SQL 的表补录进变更记录一次性操作分支并行约定 id 防冲突生产打补丁一律新增 changeset首次启动自动建表后不要再手工灌 SQL否则和 Liquibase 的记录对不上。数据库变更和代码一样也要可追溯、可回滚。Liquibase 这套跑顺了新同事拉代码一条命令就能起来省下的都是互相猜疑的时间。项目源码https://gitee.com/gzqkl/qkl-boot