# 79 Admin:迁移 Repository SQL 与并发事务到 MySQL 8 - 类型:重构 - 父级大工单:#76 - 所属 MVP / 版本:#77 - 状态:已完成,用户验收通过 - 日期:2026-08-10 - Gitea 工单:http://ilaer.eicp.net:8418/chengma/cmautobuy/issues/79 ## 背景与目标 Admin Repository 原来依赖 SQLite 的 upsert、JSON、日期、分页和写事务语义,直接更换驱动会造成查询失败或并发行为变化。本任务把生产数据访问和启动入口迁移到 MySQL 8,并保持现有页面、Client 接口和业务契约不变。 ## 最终方案 - 生产启动只读取 MySQL 环境变量,连接成功后执行追加式 MySQL schema 迁移。 - 将 upsert、JSON 函数、LIKE 转义、保留字和不限条数查询改为 MySQL 8 语法。 - 任务领取使用 `FOR UPDATE SKIP LOCKED`,状态更新和领取历史在同一事务提交。 - 首位管理员初始化通过单行哨兵锁串行;客户端绑定通过锁定客户端行串行。 - 并发同幂等键由唯一键决定赢家,失败事务回滚后读取并返回赢家响应。 - 测试使用临时 MySQL 8.4 实例,每个测试创建随机独立数据库并在结束时删除。 与建单方案的差异:幂等提交没有只依赖缺失键的间隙锁,因为多个并发事务仍可能同时通过首次查询;最终采用唯一键冲突后回滚并复用赢家响应,结果更直接且不依赖隔离级别细节。 ## 改了哪些 - `admin/main.go`:生产启动切换为 MySQL 配置、连接和迁移。 - `admin/repository/*.go`:迁移生产 SQL,并补齐 InnoDB 并发事务语义。 - `admin/repository/mysql_db.go`:追加 schema v2 管理员初始化哨兵表。 - `admin/internal/testutil/mysql.go`:提供真实 MySQL 随机测试库和安全清理。 - `admin/service/submit.go`:处理并发幂等唯一键竞争。 - `admin/**/*_test.go`:业务与路由测试切换为隔离 MySQL,历史 SQLite 迁移测试继续保留。 - `docs/admin/`:修正顺运宝缓存、JSON 函数和 SQLite 驱动用途说明。 ## 验收结果 | 验收标准 | 结果 | |---|---| | Repository 生产 SQL 可在 MySQL 8.4 执行,不依赖 SQLite 方言 | 通过 | | 并发领取同一任务只有一个客户端成功 | 通过 | | 指定/无主领取、迟到/重派结果和幂等契约保持不变 | 通过 | | 用户名和当前客户端归属唯一性、软删除规则保持一致 | 通过 | | PDD JSON、筛选、分页和状态统计结果保持一致 | 通过 | | Go 1.23 全量测试在隔离 MySQL 8.4 通过 | 通过 | ## 测试 - 执行的命令:`GOTOOLCHAIN=local go test ./... -count=1 -timeout=20m`、`GOTOOLCHAIN=local go vet ./...`、`git diff --check` - 结果:全部通过;真实 MySQL 8.4 全包测试中 `service` 用时 929.519 秒。 - **没验证到的部分**:未连接、写入或切换线上生产 MySQL;生产数据迁移和部署由 #80、#81 验证。 ## 遗留问题 - 真实 MySQL 跨公网测试每个用例独立建库,安全但耗时较长;不影响生产行为。 ## 相关提交 - `13cfced` 迁移 Admin Repository 到 MySQL 8