MD5不是加密而是哈希,仅适用于不可逆脱敏;若需脱敏,字段须为VARCHAR(32),空值需显式处理,避免索引失效;生产环境应优先用SHA2(col,256)替代,真正需还原时应使用AES_ENCRYPT()。

不能用触发器对敏感字段做 MD5 加密入库——这不是功能限制,而是语义错配:MD5 是不可逆哈希,不是加密;它不解决“数据保密”问题,只适合校验或脱敏场景。真要入库前处理,得先明确你要的是「不可逆脱敏」还是「可逆加密」。
为什么 MD5() 不该叫“加密”,而叫“哈希”
MD5() 输出固定 32 字符十六进制字符串,无密钥、无盐值、可被彩虹表快速反查。它和 AES_ENCRYPT() 有本质区别:
-
AES_ENCRYPT()需密钥,可逆,目标是保密; -
MD5()无密钥,不可逆,目标是摘要或轻量脱敏。
常见翻车点:把手机号 MD5(phone) 存进 VARCHAR(11) 字段——直接截断成 11 字符,后续比对永远失败;或者拿它当密码存,审计直接挂掉。
BEFORE INSERT 触发器里调 MD5() 的实操要点
如果确认只需脱敏(比如日志去重、统计去重),且接受不可逆,那可以在触发器里用 MD5(),但必须守住三条线:
- 目标字段类型必须是
CHAR(32)或VARCHAR(32),不能更短; - 空值和 NULL 要显式处理:
IF NEW.phone IS NOT NULL AND NEW.phone != '' THEN SET NEW.phone = MD5(NEW.phone); END IF;,否则MD5(NULL)返回NULL,掩盖业务逻辑缺陷; - 别在
WHERE或JOIN条件里现场算MD5(col)——索引失效,全表扫描。
示例(合法但仅限脱敏):
CREATE TRIGGER mask_phone_before_insert
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
IF NEW.phone IS NOT NULL AND NEW.phone != '' THEN
SET NEW.phone = MD5(NEW.phone);
END IF;
END;
比 MD5() 更靠谱的脱敏替代方案
生产环境应优先用 SHA2(col, 256) 替代 MD5(),它返回 64 字符十六进制串,抗碰撞能力更强,MySQL 8.0+ 已将 MD5() 标为不安全函数。
- 字段类型对应升级为
VARCHAR(64); - 若需兼顾可读性(如展示“138****1234”),别全哈希,改用
CONCAT('138****', SUBSTR(SHA2(phone, 256), -4)); - 真正需要还原原始值的场景,
MD5()和SHA2()都不该出现——此时必须切回AES_ENCRYPT()+VARBINARY字段 + 应用层密钥管理。
最常被忽略的一点:触发器无法区分租户、无法调 KMS、无法感知请求上下文。哪怕你硬塞进 MD5(),它也只是把脱敏逻辑锁死在数据库层,后期想按角色动态调整精度(比如管理员看全号、客服看中间四位),就得重写所有触发器——这种刚性,远比选 MD5 还是 SHA2 更致命。


















