# KV 更新复核 日期:2026-09-15。服务端 HEAD 858fe7c;KV 实现提交 a3d3faa。此次检查源码、模型、迁移、服务注册与测试内容,没有执行数据库迁移或正式存档写入。 ## 结论 先前基于 696fc8c 的“未找到 KV”结论已过期。现在已具备玩家专属 KV 的读取、批量写入和删除实现;可据此制定客户端替换方案。已实现不等于已验证正式部署,当前没有新运行测试结果。 ## 契约 所有路由 POST,前缀 playerdata,Authorize Cookie 鉴权。从 NameIdentifier 获取涂游十进制 ID,请求不传 playerId。 | 路由 | 请求 | 成功响应 | 语义 | | --- | --- | --- | --- | | /playerdata/Get | {} 或 {"keys":["Lv"]} | {"data":{"Lv":"12"}} | keys 省略/null/空列表读全部;指定列表读存在的 key,不存在项省略 | | /playerdata/Set | {"data":{"Lv":"12"}} | HTTP 200 空正文 | 覆盖已有键并新增缺失键,未提供的键保留;空字典无操作成功 | | /playerdata/Delete | {"keys":["Lv"]} | HTTP 200 空正文 | 删除指定键,缺失键忽略,空列表无操作成功 | ## 数据来源与存储 客户端玩法生成 string→string 存档 → Set 请求 data → PlayerKVService → EF SaveChangesAsync → MySQL PlayerKV。 表字段:PlayerId(bigint)、K(varchar(128))、V(longtext)、UpdateTime(datetime(6));主键 (PlayerId,K)。Get 按 Cookie 玩家 ID 查表返回字典。当前无额外 Redis 缓存,无 PlayFab 数据读取或自动导入。 已存在 AddPlayerKV 数据库迁移及 Program.cs 的 IPlayerKVService 注册。部署需应用该迁移。 ## 客户端适配要求 1. 用涂游 ID 完成 account/Login 并拿到 Cookie,之后调用 Get,成功后才初始化存档;禁止将读取失败解释为空存档。 2. PlayFabMgr 的 UpdateUserData 替换为 Set;立即同步与批量同步共用有序写入/确认机制。 3. Get 只返回 value,不返回 UpdateTime/version。现有 CompareDatas 依赖 PlayFab LastUpdated,不能保留旧时间比较、伪造服务端时间或直接拿本地时间当远端时间。需要评审云端基线加本账号待同步修改的恢复策略,或扩展响应提供版本元数据。 4. Set/Delete 200 空正文是成功;现有 CustomServerPost 成功返回空字符串,失败返回 null,调用侧不能使用 IsNullOrEmpty 判断这两个接口是否成功。优先显式 HTTP 状态/结果模型。 5. 当前仅允许读取本人数据,不等价于旧 PlayFab Public UserData;其他玩家等级等资料应使用对应玩家资料接口。 6. 保留业务 key/value 内容和账号隔离;键长度上限128。新账号空表不是旧存档已经迁移。 ## 实现边界与验证缺口 - Set 是先查后增/改,无版本比较。客户端应串行提交并正确保留失败批次;跨客户端并发无冲突检测,同时首次插入同键可能触发主键竞争。后续按所需并发保证评审,不能把它描述成具备原子数据库 upsert 的契约。 - 存在 7 个 EF InMemory 单测,覆盖全量/指定键读、覆盖新增、空写、删除、空删与账号隔离。本次只阅读测试,未运行;它们也不证明真实 MySQL 并发、迁移或 HTTP Cookie 鉴权通过。 - s101 是否部署新接口、迁移是否生效、实际读写/重登恢复仍待联调验证。 ## 关键源码 - LeaderboardAPI/Controllers/PlayerDataApi.cs - LeaderboardBLL/Models/PlayerKVModel.cs - LeaderboardBLL/Services/PlayerKV/PlayerKVService.cs - LeaderboardBLL/Models/DBModel.cs - LeaderboardBLL/Migrations/20260915093852_AddPlayerKV.cs - LeaderboardBLL.Test/Services/PlayerKV/PlayerKVServiceTests.cs