必须建在患者病历主表(如patient_records)上,因触发器需响应主表的INSERT/UPDATE/DELETE操作;历史表仅被动接收日志,建在其上无法捕捉业务变更。

触发器该建在病历表还是历史表上
必须建在患者病历主表(比如 patient_records)上,而不是历史表。触发器本质是响应主表的 INSERT/UPDATE/DELETE 操作,历史表只是被动接收日志的地方。如果建错位置,修改根本不会被捕捉。
常见错误是试图在历史表上建 BEFORE INSERT 触发器来“拦截”写入——这毫无意义,因为历史表本就不该被业务逻辑直接写入,它的数据应完全由主表变更驱动。
UPDATE 触发器里怎么判断字段是否真被改了
直接比较 OLD.column_name != NEW.column_name 不可靠:NULL 值会让整个表达式为 NULL,导致条件失效;文本字段还可能因空格、换行差异误判。必须显式处理 NULL:
IF (OLD.diagnosis IS NULL) != (NEW.diagnosis IS NULL) OR (OLD.diagnosis != NEW.diagnosis) THEN -- 确认 diagnosis 字段实际变化 END IF;
- 用
(OLD.x IS NULL) != (NEW.x IS NULL)先比 NULL 性 - 再用
OLD.x != NEW.x比值(前提是两者都不为 NULL) - 对文本字段,可加
TRIM()或REPLACE(NEW.note, '\r\n', '\n')统一格式再比
INSERT/UPDATE/DELETE 三种操作的日志字段怎么设计才不漏信息
单条日志记录必须包含:record_id(原病历 ID)、operation_type('I'/'U'/'D')、old_data 和 new_data(JSON 格式,只存真正变动的字段)、modified_by(从会话变量 @current_user_id 取)、modified_at(用 NOW(3) 带毫秒)。
关键细节:
-
old_data在INSERT时为NULL,DELETE时存完整旧行,UPDATE时只存变化字段 - 不要把整行 JSON 化后塞进日志表——字段太多会导致日志体积暴涨,查起来也慢
-
modified_by不能依赖应用层传参,必须在触发器里读数据库会话变量,否则绕过应用直连 DB 就会丢失责任人
触发器执行失败会导致主事务回滚吗
会。MySQL 中触发器属于当前事务的一部分,一旦触发器内抛出异常(比如向日志表插入时违反唯一约束、字段超长),整个 UPDATE 操作都会失败并回滚——患者病历改不了,连带日志也没记成。
规避方法只有两个:
- 确保日志表结构宽松:所有文本字段用
TEXT,时间字段用DATETIME(3),不设非空以外的约束 - 绝对不要在触发器里调用存储过程或外部服务——网络延迟或失败会直接卡死主流程
医疗系统里,宁可日志少几条,也不能让病历保存失败。这点比“日志完整性”重要得多。

















