Files
danyang-match/docs
WorkBuddy 0242ea44e8 fix(mapper): 补 5 个「只有声明、无任何 SQL」的方法;新建 Mapper 绑定守卫持续挡住该类缺陷
全仓无 mapper XML、无自定义 ISqlInjector,自定义方法只能靠注解提供 SQL。
这 5 个方法漏写注解,编译期无感知,调用必抛 Invalid bound statement:
  UserPrivacySettingsMapper.findByUserId  —— 隐私设置读取
  UserPreferenceMapper.findByUserId      —— 推荐引擎 / 匹配资格共 6 处调用
  ReviewReasonMapper.findAllEnabled      —— 审核原因字典下拉
  ReviewReasonMapper.findByCategory
  ReviewItemMapper.findByReviewTaskId
长期未被发现的原因:候选池为空(分支走不到)+ 测试库根本没有这 4 张表(双重不可达)。
补的 SQL 一律带 AND deleted_at IS NULL —— V037 之后这些表都有软删列,
只看 V002 建表会漏掉软删过滤,制造「读到已删数据」的新缺陷。

test(invariants): MapperBindingGuardTest —— 三用例
① 绑定守卫:反射遍历 MapperRegistry 全部 Mapper 的声明方法,hasStatement 为假即失败;
   按「实体有无主键」语义豁免复合主键实体的 selectById/updateById/deleteById 等
   (MP 本就不为无主键实体注入,属正确行为;非类名白名单,故新增复合主键表同样适用)。
② 探测自检:虚构 statementId 必须为假,防断言静默永真。
③ 可执行性:插真实数据后真查一遍 —— 绑定存在 ≠ 能跑(本次即借此确认 JsonNode 映射无碍)。
负向注入已验证:移除 ReviewItemMapper 的 @Select → 守卫报恰 1 项缺失,
且可执行性用例抛真实 Invalid bound statement;还原后复跑全绿。

test(db): schema-h2.sql 补 4 张缺失表(user_privacy_settings / user_preferences /
review_reasons / review_items),按 V002 + V037 之后的最终态建模(含 id、deleted_at 与
11 个匹配权重列),并保留 chk_item_type / chk_item_status / chk_pref_priority 约束。

docs(plan): 附 B 新增第 12 项;更正第 11 项中我自己上一轮的错误断言
—— 「表无 id 列导致 insert 必崩」不成立:V037 已补齐 id/deleted_at/权重列。
真实缺陷是 updatePrivacySettings 对已存在记录也走 insert(非 upsert)→ 第二次更新撞主键冲突。
方法论:判断表结构必须遍历全部迁移,只看 CREATE TABLE 会得出与生产相反的结论。
2026-09-19 15:26:35 +08:00
..
2026-09-09 22:05:00 +08:00