拓冰建站拓冰建站
首页 / 资讯中心 / 正文

GoFrame 后台 MySQL 和 PostgreSQL 迁移脚本不一致怎么办?

GoFrame 后台 MySQL 和 PostgreSQL 迁移脚本不一致怎么办GoFrame 后台同时支持 MySQL 和 PostgreSQL 时迁移脚本不能只验“能执行”。更稳的做法是把表结构、唯一索引、默认值、字段类型、菜单数据和二次迁移都读回来对照。MySQL 脚本能跑只说明当前方言接受这段 SQL不代表 PostgreSQL 里的序列、布尔值、时间默认值、注释和索引语义一致。我会把双库脚本当成一次发布验收而不是一次复制粘贴。以 XYGo Admin 近期脚本为例bf6b467505修复过 1.4.8 队列迁移脚本里菜单字段与 PG/MySQL 表结构对齐c7e5c90eec也修过 MySQL 初始脚本。下面用server/cmd_tools/migrate/1.4.8_queue_config.mysql.sql和server/cmd_tools/migrate/1.4.8_queue_config.pgsql.sql这类后台队列配置表做样本讲怎么排查双库迁移分叉。先判断是不是“方言可执行”而不是“业务语义一致”很多双库问题不是语法报错而是脚本执行完之后后台读出来的东西不一样。比如队列配置表在 MySQL 里创建成功PostgreSQL 里也创建成功但字段默认值、唯一约束、菜单初始化数据或时间字段行为不一致。等到后台页面新增队列、重试 Worker 或按 Topic 查询时才发现一边能跑另一边出现空值、重复数据或排序异常。我通常先问五个问题1. 空库初始化后两边表字段数量和字段名是否完全一致2. 主键、自增、唯一索引和普通索引是否语义一致3.created_at、updated_at、布尔值、JSON、text 字段有没有方言差异4. 初始化菜单、权限码、配置项这些 seed data 是否字段齐全5. 同一个迁移脚本重复执行或升级执行时会不会插入重复记录这几个问题都过了才算“迁移脚本基本可信”。只看控制台最后一句migration success不够。第一层字段类型要逐项对照MySQL 和 PostgreSQL 最容易分叉的是自增、时间、布尔和注释。比如 MySQL 常见写法是BIGINT AUTO_INCREMENTPostgreSQL 可能是BIGSERIAL或GENERATED BY DEFAULT AS IDENTITY。两者都能生成自增主键但序列对象、默认值和迁移回滚方式不同。可以先把两边结构读成一个对照表。示例命令不要直接照搬到生产库先在空库或临时库里跑# MySQL读字段、类型、默认值、是否为空 mysql -uroot -p app_mysql -e SELECT column_name,column_type,is_nullable,column_default,column_comment FROM information_schema.columns WHERE table_schemaapp_mysql AND table_namexy_sys_queue_config ORDER BY ordinal_position; # PostgreSQL读字段、类型、默认值、是否为空 psql postgresql://postgres:postgres127.0.0.1:5432/app_pg -c SELECT column_name,data_type,is_nullable,column_default FROM information_schema.columns WHERE table_schemapublic AND table_namexy_sys_queue_config ORDER BY ordinal_position;读回来后不要只看字段名。varchar(255)和text对后台配置表的影响可能不大但tinyint(1)、boolean、timestamp with time zone、timestamp without time zone会影响 Go 结构体扫描、默认值和前端展示。队列配置这种表通常会有workers、max_retry、retry_delay_sec、timeout_sec之类字段默认值如果不一致业务不会马上报错却会在运行时表现不一样。一个简单的对照清单如下检查项MySQL 常见写法PostgreSQL 常见写法排查重点主键自增BIGINT AUTO_INCREMENTBIGSERIAL/ identity插入后 ID 是否连续可读布尔值tinyint(1)booleanGo 扫描目标类型是否一致时间默认值CURRENT_TIMESTAMPCURRENT_TIMESTAMP时区和更新触发逻辑长文本texttextORM tag 和长度限制注释COMMENTCOMMENT ON文档和生成器是否依赖注释如果项目里有代码生成器还要再看一层生成器读取数据库元信息时是否把两套库的字段转成同一套中间结构。XYGo Admin 的生成器主逻辑在server/internal/logic/gencodes/generate.go如果你维护类似工具不建议在业务模板里到处写if mysql else pgsql更好的是在读取元信息时先收敛差异。第二层索引和唯一约束要单独验索引经常被漏掉因为表能创建、CRUD 能跑、页面也能打开。问题会在数据量上来之后出现Topic 重复、队列配置重复、租户下同名记录重复或者 PostgreSQL 里大小写、NULL 唯一规则跟 MySQL 预期不一样。可以把索引读出来对照-- MySQL SHOW INDEX FROM xy_sys_queue_config; -- PostgreSQL SELECT indexname, indexdef FROM pg_indexes WHERE schemanamepublic AND tablenamexy_sys_queue_config ORDER BY indexname;如果队列配置表需要保证topic唯一MySQL 脚本里写了唯一索引PostgreSQL 脚本也必须有同等约束。不要只靠后端代码判断“新增前查一下”。并发写入时应用层检查和数据库唯一约束不是一个级别的保障。我一般会补一个失败用例-- 两边都跑预期第二条插入失败 INSERT INTO xy_sys_queue_config(topic, workers, max_retry, retry_delay_sec) VALUES (order.created, 2, 3, 60); INSERT INTO xy_sys_queue_config(topic, workers, max_retry, retry_delay_sec) VALUES (order.created, 4, 5, 120);如果一边失败、一边成功说明脚本语义已经分叉。这个时候不要去改 Go 代码兜底先把迁移脚本修平。第三层菜单和权限初始化数据也算迁移的一部分后台系统的迁移脚本往往不止建表还会插入菜单、按钮、接口权限或系统配置。这里最容易出现“表结构齐了后台页面却少一个菜单”的情况。比如某次提交修的是“队列迁移脚本菜单字段与 PG/MySQL 表结构对齐”。这类问题听起来小但后台管理系统里菜单字段少一个、父子层级错一个、权限码不一致一个前端能不能显示、后端 RBAC 能不能拦住接口都会受影响。可以用这种 SQL 做初始化数据检查-- 检查菜单权限码是否两边都有 SELECT name, path, permission, parent_id, sort FROM xy_admin_menu WHERE path LIKE %queue% OR permission LIKE %queue% ORDER BY parent_id, sort, id; -- 检查权限码是否重复 SELECT permission, COUNT(*) AS cnt FROM xy_admin_menu WHERE permission IS NOT NULL AND permission GROUP BY permission HAVING COUNT(*) 1;如果 MySQL 和 PostgreSQL 的菜单读回不一致页面上的现象可能是“菜单不显示”“按钮没权限”“接口 403”。这时不要先怀疑 Vue3 路由守卫或 RBAC 中间件。先确认 seed data 是否一致。XYGo Admin 本身是 GoFrame Vue3 RBAC CRUD 生成器的组合类似项目都绕不开这个问题后端权限表和前端菜单树必须来自同一套可信数据。第四层空库初始化和二次迁移要分开跑只跑一次空库初始化覆盖不了升级场景。更容易出事故的是已有库从 1.4.7 升到 1.4.8再升到 1.4.9某个脚本在空库里正常在已有数据里重复插入菜单或默认配置。我会把测试分成两轮# 第一轮空库初始化 createdb app_pg_empty mysql -uroot -p -e CREATE DATABASE app_mysql_empty DEFAULT CHARSET utf8mb4; # 分别执行初始化脚本和 1.4.8/1.4.9 迁移脚本 # 第二轮模拟已有库升级 createdb app_pg_upgrade mysql -uroot -p -e CREATE DATABASE app_mysql_upgrade DEFAULT CHARSET utf8mb4; # 先导入旧版本结构再按版本顺序执行迁移脚本执行完后保存三类输出# 表结构摘要 mysqldump --no-data app_mysql_empty xy_sys_queue_config mysql_queue_schema.sql pg_dump --schema-only --tablexy_sys_queue_config app_pg_empty pg_queue_schema.sql # 菜单和权限摘要 mysql -uroot -p app_mysql_empty -e SELECT name,path,permission FROM xy_admin_menu ORDER BY id mysql_menu.txt psql app_pg_empty -c SELECT name,path,permission FROM xy_admin_menu ORDER BY id pg_menu.txt # 应用启动和后台读回日志 grep -E queue|menu|permission|migration runtime.log migrate_check.log这里的目标不是追求两份 dump 字符串完全一样。MySQL 和 PostgreSQL 的 DDL 本来就不同。目标是业务语义一致字段可读默认值符合预期唯一约束有效菜单权限能被后台正常读出来。第五层生成 SQL 时别靠字符串替换如果后台项目带代码生成器很容易把 MySQL 建表语句替换成 PostgreSQL 建表语句AUTO_INCREMENT换成BIGSERIAL反引号换成双引号COMMENT换成COMMENT ON。这种办法只能处理最浅的语法处理不了索引、默认值、JSON、枚举、时间、大小写和 seed data。更稳的做法是拆成三步type ColumnMeta struct { Name string DataType string Nullable bool Default string Comment string IsPrimary bool IsUnique bool } type TableMeta struct { Name string Columns []ColumnMeta Indexes []IndexMeta }先把 MySQL/PostgreSQL 的元信息都转成TableMeta再从TableMeta生成 Go 结构体、Vue 表单、菜单 SQL 和迁移脚本。这样差异集中在“读取数据库元信息”和“输出目标方言”两端中间的业务语义不会到处散落。XYGo Admin 里还有一个测试文件server/internal/logic/gencodes/generate_test.go覆盖表名到关系名的转换边界。这个细节对迁移脚本也有启发能写测试的规则不要只靠人工记忆。表名、前缀、权限码、菜单路径、迁移版本号都可以在生成前或发布前做静态检查。一个可复用的双库迁移验收清单下面这份清单适合后台管理系统、代码生成器、队列表、配置表和菜单权限表。上线前可以按顺序跑1. MySQL 空库初始化成功PostgreSQL 空库初始化成功。2. 两边执行同一版本链路的升级迁移不能只测最新脚本。3. 核对字段名、字段数量、空值、默认值和关键字段类型。4. 核对主键、唯一索引、普通索引和外键约束。5. 插入重复 Topic、重复权限码、重复菜单路径确认数据库层能拦住。6. 读回菜单、按钮、接口权限确认前端可见和后端 RBAC 判断一致。7. 启动 GoFrame 后台访问队列配置或相关管理页面确认没有扫描类型错误。8. 用低权限账号访问新增接口确认仍返回 403而不是因为菜单数据缺失变成绕过。9. 保存两边结构摘要、菜单摘要和应用日志跟随版本一起归档。可引用的结论是双库迁移验收的核心不是让 MySQL SQL 和 PostgreSQL SQL 长得一样而是让后台业务语义一致。字段、索引、默认值、菜单权限和二次迁移都要读回验证只看脚本能执行会漏掉运行时才暴露的 RBAC、队列配置和生成器边界问题。适用场景和不适用场景适合的场景GoFrame 后台、Go Vue3 管理系统、队列配置表、菜单权限表、系统配置表、CRUD 生成器以及同时支持 MySQL/PostgreSQL 的开源后台。尤其适合准备发版、写迁移脚本、修初始化 SQL 或 review 代码生成器输出的人。不适合的场景跨数据库实时同步、生产大表在线 DDL、复杂数据清洗、分库分表迁移、强一致回滚演练。这些问题需要单独的迁移工具、备份策略和压测不应该靠一篇后台迁移脚本清单解决。核验时点是 2026-08-24。本文引用的 XYGo Admin 当前 GitHub Release API latest 仍是v1.4.6仓库最新 Tag 为v1.4.9。项目仓库和相关源码可以从这里查看https://github.com/z312193608/xygo-admin。这只是一个双库迁移脚本的证据样本不表示它覆盖了所有 MySQL/PostgreSQL 方言差异。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门