--- name: 缓存数据库表重构 overview: 重构数据库缓存模块,将 cached 表替换为符合设计规范的 hotime_cache 表,支持 MySQL/SQLite/PostgreSQL,修复并发问题,支持可配置的历史记录功能和自动迁移。 todos: - id: update-cache-db content: 重构 cache_db.go:新表、UPSERT、历史记录、自动迁移、问题修复 status: completed - id: update-cache-go content: 修改 cache.go:添加 HistorySet 配置传递 status: completed - id: update-makecode content: 修改 makecode.go:跳过新表名 status: completed --- # 缓存数据库表重构计划 ## 设计概要 将原 `cached` 表替换为 `hotime_cache` 表,遵循数据库设计规范,支持: - 多数据库:MySQL、SQLite、PostgreSQL - 可配置的历史记录功能(仅日志,无读取接口) - 自动迁移旧 cached 表数据 ## 文件改动清单 | 文件 | 改动 | 状态 | |------|------|------| | [cache/cache_db.go](cache/cache_db.go) | 完全重构:新表、UPSERT、历史记录、自动迁移 | 待完成 | | [cache/cache.go](cache/cache.go) | 添加 `HistorySet: db.GetBool("history")` 配置传递 | 待完成 | | [code/makecode.go](code/makecode.go) | 跳过 hotime_cache 和 hotime_cache_history | 已完成 | ## 表结构设计 ### 主表 `hotime_cache` ```sql -- MySQL CREATE TABLE `hotime_cache` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `key` varchar(64) NOT NULL COMMENT '缓存键', `value` text DEFAULT NULL COMMENT '缓存值', `end_time` datetime DEFAULT NULL COMMENT '过期时间', `state` int(2) DEFAULT '0' COMMENT '状态:0-正常,1-异常,2-隐藏', `create_time` datetime DEFAULT NULL COMMENT '创建日期', `modify_time` datetime DEFAULT NULL COMMENT '变更时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_key` (`key`), KEY `idx_end_time` (`end_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='缓存管理'; -- SQLite CREATE TABLE "hotime_cache" ( "id" INTEGER PRIMARY KEY AUTOINCREMENT, "key" TEXT NOT NULL UNIQUE, "value" TEXT, "end_time" TEXT, "state" INTEGER DEFAULT 0, "create_time" TEXT, "modify_time" TEXT ); -- PostgreSQL CREATE TABLE "hotime_cache" ( "id" SERIAL PRIMARY KEY, "key" VARCHAR(64) NOT NULL UNIQUE, "value" TEXT, "end_time" TIMESTAMP, "state" INTEGER DEFAULT 0, "create_time" TIMESTAMP, "modify_time" TIMESTAMP ); CREATE INDEX "idx_hotime_cache_end_time" ON "hotime_cache" ("end_time"); ``` ### 历史表 `hotime_cache_history`(配置开启时创建,创建后永不自动删除) 与主表结构相同,但 `id` 改为 `hotime_cache_id` 作为外键关联。 ## 问题修复清单 | 问题 | 原状态 | 修复方案 | |------|--------|----------| | key 无索引 | 全表扫描 | 唯一索引 uk_key | | 并发竞态 | Update+Insert 可能重复 | 使用 UPSERT 语法 | | 时间字段混乱 | time(纳秒) + endtime(秒) | 统一 datetime 格式 | | value 长度限制 | varchar(2000) | TEXT 类型 | | TimeOut=0 立即过期 | 无默认值 | 默认 24 小时 | | get 时删除过期数据 | 每次写操作 | 惰性删除,只返回 nil | | 旧表 key 重复 | 无约束 | 迁移时取最后一条 | | value 包装冗余 | `{"data": value}` | 直接存储 | ## 主要代码改动点 ### cache_db.go 改动 1. 新增常量:表名、默认过期时间 24 小时 2. 结构体添加 `HistorySet bool` 3. 使用 common 包 `Time2Str(time.Now())` 格式化时间 4. `initDbTable()`: 支持三种数据库、自动迁移、创建历史表 5. `migrateFromCached()`: 去重迁移(取最后一条)、删除旧表 6. `writeHistory()`: 查询数据写入历史表(仅日志) 7. `set()`: 使用 UPSERT、调用 writeHistory 8. `get()`: 惰性删除 9. `Cache()`: TimeOut=0 时用默认值 ### cache.go 改动 第 268 行添加:`HistorySet: db.GetBool("history")` ## 配置示例 ```json { "cache": { "db": { "db": true, "session": true, "timeout": 72000, "history": false } } } ``` ## 历史记录逻辑 - 新增/修改后:查询完整数据,id 改为 hotime_cache_id,插入历史表 - 删除:不记录历史 - 历史表仅日志记录,无读取接口,人工在数据库操作