Files
kyugao dd98b4d45b docs(迭代06): 数据存储SQLite迭代文档 + 需求归档(R-008)
- 新增 02-计划/计划-数据存储SQLite.md(PLAN-007)
- 新增 04-迭代记录/06-数据存储SQLite/ 五份文档(迭代目标/技术实现方案/验收标准/UI交互调用分析/迭代复盘)
- 归档 R-008 至 已完成/(含归档头 + 讨论记录索引),索引更新为已实现(已归档)
- 设计约束更新:技术方案约束-012 标注 SQLite 变更、数据存储设计.md 第 9 节变更预告
- 需求池说明.md 新增「归档与转正规范」;迭代记录说明.md 新增「实现经验沉淀」
- 验收标准修正 db 文件名笔误(one-divine-lot.db → store.db)
2026-09-01 18:04:28 +08:00

43 lines
3.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 迭代复盘:06-数据存储SQLiteJSON → SQLite
> 复盘日期:2026-09-01 | 迭代状态:**已完成(验收通过)**
> 关联需求:R-008(数据存储管理 JSON → SQLite,已定稿)
> 关联计划:PLAN-007(数据存储 SQLite 化)
## 结果
迭代 06 达成:数据存储从 JSON data storestore.json / store.market.json / store.schema.json)升级为 SQLitestore.dbnode:sqlite),仅存储引擎替换、对外行为不变。真实数据迁移完成(15 条持仓 + 13 条行情),JSON 清理废弃,份额/行情/设置功能全部不回归。
## 过程事实
1. **技术选型验证**node:sqliteNode 22.23.1 内置,DatabaseSyncSQLite 3.51.3)实测可用;better-sqlite3 需原生编译 → 选 node:sqlite(零依赖分发,experimental 风险由 SqliteStore 封装隔离);
2. **表结构**strategy_holdings(持仓生命周期表:holding_id 自增 + strategy_id/code/shares/created_at/closed_at + 部分唯一索引)+ market_quotes_cachecode 主键 + last_price/last_close/updated_at 两列);不建 tradesR-007 再建);
3. **SqliteStore 封装**:init/迁移/持仓生命周期(openHolding/addShares/reduceShares/closeHolding/行情读写/close
4. **DataStore 改造**:门面委托 SqliteStore,保留兼容 APIgetDataset/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 等(幂等跳过),保留用于新环境初始化。