# 迭代复盘:06-数据存储SQLite(JSON → SQLite) > 复盘日期:2026-09-01 | 迭代状态:**已完成(验收通过)** > 关联需求:R-008(数据存储管理 JSON → SQLite,已定稿) > 关联计划:PLAN-007(数据存储 SQLite 化) ## 结果 迭代 06 达成:数据存储从 JSON data store(store.json / store.market.json / store.schema.json)升级为 SQLite(store.db,node:sqlite),仅存储引擎替换、对外行为不变。真实数据迁移完成(15 条持仓 + 13 条行情),JSON 清理废弃,份额/行情/设置功能全部不回归。 ## 过程事实 1. **技术选型验证**:node:sqlite(Node 22.23.1 内置,DatabaseSync,SQLite 3.51.3)实测可用;better-sqlite3 需原生编译 → 选 node:sqlite(零依赖分发,experimental 风险由 SqliteStore 封装隔离); 2. **表结构**:strategy_holdings(持仓生命周期表:holding_id 自增 + strategy_id/code/shares/created_at/closed_at + 部分唯一索引)+ market_quotes_cache(code 主键 + last_price/last_close/updated_at 两列);不建 trades(R-007 再建); 3. **SqliteStore 封装**:init/迁移/持仓生命周期(openHolding/addShares/reduceShares/closeHolding)/行情读写/close; 4. **DataStore 改造**:门面委托 SqliteStore,保留兼容 API(getDataset/getAllDatasets/行情读写),启动检测自动迁移(幂等); 5. **PositionManager 适配**:整策略 dataset 重写(_setShares)→ 单票生命周期(_applySharesForStrategy 绝对目标语义); 6. **迁移脚本**:scripts/migrate-json-to-sqlite.mjs + pnpm migrate 命令(一次性 + 启动自动迁移共用逻辑); 7. **真实迁移**:15 持仓 + 13 行情迁入 SQLite,与迁移前逐条一致;JSON 备份 .bak 后清理删除(仅留 store.db); 8. **移除「一键清零」按钮**(老师决定):前端按钮/弹窗 + 后端 remove-all-shares 端点移除;clearStrategyShares 保留(删除策略联动)。 ## 经验教训(复盘沉淀) ### 1. 语义迁移必须逐方法核对(重要) - **教训**:改造 PositionManager 时,把 addToStrategy 的「新增量」误当「绝对目标份额」传给生命周期方法,导致加仓 100 变 100 —— 真实 API 验证时发现(600719.SH 手动做T 少了 100 股),已修复并回滚数据; - **沉淀**:方法语义变更(增量 vs 绝对量)必须显式命名(_applySharesForStrategy 接收 target 绝对目标),调用方逐处核对;改造后必须用真实 API 走一遍 CRUD 回归,不能只靠隔离单测。 ### 2. node:sqlite 的锁行为 - 插件进程持有 SQLite 连接时,外部脚本再开连接写库会报 `attempt to write a readonly database`; - **沉淀**:真实数据修正必须走插件自己的 API(或停机后操作),外部脚本只能读;测试写操作用 ODL_TEST_DATA_DIR 隔离(技术约束-011)。 ### 3. 关闭连接 - 插件 dispose 时必须 storage.close()(关闭 SQLite 连接),避免资源泄漏。 ### 4. 文档与实际必须一致 - 验收标准初稿写 `one-divine-lot.db`,实际实现用 `store.db` —— 归档前已修正。 ## 遗留/后续 1. **盘中行情写 SQLite 验证**:本次验收时已收盘,无实时推送;开盘后应确认行情防抖写回 store.db(观察 updated_at / 文件 mtime); 2. **R-007 交易记录关联**:strategy_holdings.holding_id 已就绪,可作为 trades 表关联锚点(R-007 实现时建 trades 表); 3. **SqliteStore 迁移逻辑引用旧文件名**:migrateJson 仍检查 store.json 等(幂等跳过),保留用于新环境初始化。