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 会得出与生产相反的结论。
This commit is contained in:
@@ -559,5 +559,74 @@ CREATE TABLE idempotency_records (
|
||||
CONSTRAINT chk_idempotency_state CHECK (state IN ('PROCESSING', 'COMPLETED'))
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Phase 23 补齐(2026-09-19):以下 4 张表此前在测试库完全不存在。
|
||||
-- 发现经过:MapperBindingGuardTest 报出 5 个「声明了却无 @Select」的方法,
|
||||
-- 其中 4 个方法对应的表正是这 4 张 —— 表不存在 + 语句未绑定 = 双重盲区,
|
||||
-- 任何测试都走不到这些代码路径,缺陷被"空数据 + 缺表"共同掩盖。
|
||||
-- 保真口径:**按 V002 + V037 之后的最终状态**建模,不是按 V002 的初始建表。
|
||||
-- V037(align_entity_columns_with_migrations)已给这 4 张表补上 BaseEntity 公共列
|
||||
-- (id / created_at / updated_at / deleted_at)与匹配权重列 ——
|
||||
-- 若只看 V002 会误判为「表主键是 user_id、无 id 列」,进而写出错误的 SQL。
|
||||
-- 尤需注意 deleted_at:4 张表**全部**已有软删列,故相关查询必须带 deleted_at IS NULL。
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- V002 + V037: user_preferences 择偶偏好
|
||||
-- V002 初始:user_id 为主键,无 id / deleted_at / 权重列
|
||||
-- V037 补齐:id + deleted_at + 11 个匹配权重列
|
||||
CREATE TABLE user_preferences (
|
||||
user_id VARCHAR(36) PRIMARY KEY, id VARCHAR(36),
|
||||
min_age INT, max_age INT, age_priority VARCHAR(16),
|
||||
min_height_cm INT, max_height_cm INT, height_priority VARCHAR(16),
|
||||
region_scope CLOB, region_priority VARCHAR(16),
|
||||
marital_statuses CLOB, marital_priority VARCHAR(16),
|
||||
min_education_code VARCHAR(32), education_priority VARCHAR(16),
|
||||
children_acceptance VARCHAR(32), children_priority VARCHAR(16),
|
||||
smoking_preference VARCHAR(32), drinking_preference VARCHAR(32),
|
||||
settlement_preference VARCHAR(32), marriage_plan_preference VARCHAR(32),
|
||||
age_weight DOUBLE PRECISION DEFAULT 0.15, region_weight DOUBLE PRECISION DEFAULT 0.20,
|
||||
marital_weight DOUBLE PRECISION DEFAULT 0.10, children_weight DOUBLE PRECISION DEFAULT 0.05,
|
||||
education_weight DOUBLE PRECISION DEFAULT 0.10, height_weight DOUBLE PRECISION DEFAULT 0.05,
|
||||
marriage_plan_weight DOUBLE PRECISION DEFAULT 0.15, lifestyle_weight DOUBLE PRECISION DEFAULT 0.10,
|
||||
settlement_weight DOUBLE PRECISION DEFAULT 0.05, interest_weight DOUBLE PRECISION DEFAULT 0.10,
|
||||
created_at TIMESTAMP WITH TIME ZONE, updated_at TIMESTAMP WITH TIME ZONE,
|
||||
deleted_at TIMESTAMP WITH TIME ZONE,
|
||||
CONSTRAINT chk_pref_priority CHECK (age_priority IN ('required', 'preferred'))
|
||||
);
|
||||
|
||||
-- V002 + V037: user_privacy_settings 隐私设置
|
||||
-- V037 补齐:id + deleted_at(V002 时无此两列)
|
||||
CREATE TABLE user_privacy_settings (
|
||||
user_id VARCHAR(36) PRIMARY KEY, id VARCHAR(36),
|
||||
visible_in_recommendations BOOLEAN DEFAULT TRUE, visible_in_search BOOLEAN DEFAULT TRUE,
|
||||
show_occupation BOOLEAN DEFAULT TRUE, show_lifestyle_photos BOOLEAN DEFAULT TRUE,
|
||||
receive_activity_recommendations BOOLEAN DEFAULT TRUE,
|
||||
accept_matchmaker_recommendations BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP WITH TIME ZONE, updated_at TIMESTAMP WITH TIME ZONE,
|
||||
deleted_at TIMESTAMP WITH TIME ZONE
|
||||
);
|
||||
|
||||
-- V003 + V037: review_reasons 审核原因字典
|
||||
-- 注意主键是 code(业务以 code 引用),V037 额外补 id 列以承接 BaseEntity 语义。
|
||||
-- V037 补:id + created_at + updated_at + deleted_at
|
||||
CREATE TABLE review_reasons (
|
||||
code VARCHAR(64) PRIMARY KEY, id VARCHAR(36), name VARCHAR(128),
|
||||
category VARCHAR(32), enabled BOOLEAN DEFAULT TRUE, sort_order INT DEFAULT 0,
|
||||
created_at TIMESTAMP WITH TIME ZONE, updated_at TIMESTAMP WITH TIME ZONE,
|
||||
deleted_at TIMESTAMP WITH TIME ZONE
|
||||
);
|
||||
|
||||
-- V003 + V037: review_items 审核项
|
||||
-- V037 补:deleted_at
|
||||
CREATE TABLE review_items (
|
||||
id VARCHAR(36) PRIMARY KEY, review_task_id VARCHAR(36),
|
||||
item_type VARCHAR(32), status VARCHAR(32) DEFAULT 'pending',
|
||||
reason_code VARCHAR(64), comment VARCHAR(500),
|
||||
created_at TIMESTAMP WITH TIME ZONE, updated_at TIMESTAMP WITH TIME ZONE,
|
||||
deleted_at TIMESTAMP WITH TIME ZONE,
|
||||
CONSTRAINT chk_item_type CHECK (item_type IN ('avatar', 'lifestyle_photos', 'basic_profile', 'self_intro', 'relationship_profile')),
|
||||
CONSTRAINT chk_item_status CHECK (status IN ('pending', 'approved', 'need_edit', 'abnormal'))
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX uk_idempotency_scope
|
||||
ON idempotency_records (actor_id, endpoint, idempotency_key);
|
||||
|
||||
Reference in New Issue
Block a user