feat(db): SQLite 全量迁移至 MySQL(config.yaml 配置化 + 迁移脚本 + 一致性校验)

- config.yaml database.mysql:host/port/db/user/charset 明文可提交;密码经 password_env
  引用 .env 的 MYSQL_PASSWORD(AGENT.md §33 密钥不进 git)
- config.py _build_mysql_url:URL 优先级 DATABASE_URL env > database.mysql 段 > sqlite 兜底
- pyproject 引入 pymysql>=1.1
- tests/conftest.py 强制每进程 /tmp SQLite(测试绝不触 MySQL 开发库);test_config 覆盖
  mysql 组装/密码可选/sqlite 兜底分支
- scripts/migrate_sqlite_to_mysql.py:sqlite→mysql 一次性迁移工具(keyset 分页 + chunk
  多值 INSERT + 攒批 commit + 幂等续传 + 低配 MySQL 节流 --throttle-sec + --verify-only
  行数与抽样一致性校验);已用于 data/quant.db 约 1605 万行迁移并经校验一致
This commit is contained in:
Simon
2026-09-08 23:58:48 +08:00
parent a3fabf9ae9
commit 6c2f198261
8 changed files with 409 additions and 20 deletions
+7 -1
View File
@@ -1,8 +1,10 @@
"""全局测试配置。
- 强制 SQLite 临时文件数据库:默认库已是 MySQL(config.yaml database.mysql),
测试绝不允许触碰开发 MySQL(qlib@192.168.1.10);该 env 在 app 模块
首次导入前生效,SessionLocal/engine 会按它构造。
- JOB_MODE=local:单测/CI 里 Job 在本进程执行(不 spawn 子进程、不依赖安装态)
- QLIB_SKIP_STALE_JOB_CLEANUP=1:TestClient 启动 lifespan 不清理残留 Job
(避免连接/写入开发库 data/quant.db)
必须在任何 app / config 模块首次导入前生效,故放在 conftest 模块顶层。
"""
@@ -11,6 +13,10 @@ from __future__ import annotations
import os
# 测试数据库:每进程唯一 /tmp sqlite 文件(隔离、不落项目目录、不触 MySQL)
_TEST_DB = f"/tmp/qlib-pytest-{os.getpid()}.db"
os.environ["DATABASE_URL"] = f"sqlite:///{_TEST_DB}"
# 强制(不是 setdefault):测试绝不 spawn 研究子进程 / 不触碰开发库
os.environ["JOB_MODE"] = "local"
os.environ["QLIB_SKIP_STALE_JOB_CLEANUP"] = "1"