SQL触发器不能直接删除Redis缓存,因数据库内核不支持网络调用,强行执行redis-cli DEL或UDF会报ERROR 1418、1422等错误;正确做法是通过中间表记录待失效key,由外部轮询服务安全清理。

SQL触发器不能直接删除 Redis 缓存,这是架构层面的硬限制——数据库内核不支持网络调用,任何试图在触发器里执行 redis-cli DEL 或封装 UDF 调用 Redis 的做法,都会在解析、权限或运行时失败,典型报错包括 ERROR 1418(函数未声明特性)、ERROR 1422(隐式提交被禁止),或日志中反复出现 Can't find symbol 'redis_del'。
为什么触发器里写 DEL 命令根本走不通
MySQL / PostgreSQL / SQL Server 的触发器都运行在事务上下文内,所有操作必须满足 ACID,而网络 I/O 是不可控、不可回滚、不可审计的。即使绕过语法校验(比如用自定义函数),实际调用也会卡在系统调用层,导致事务长时间挂起、连接堆积、主从延迟加剧。这不是配置没调好,是设计上就不该这么干。
用中间表记录待失效 key 是唯一可靠路径
触发器只做最轻量的事:把要删的缓存 key 写进一张日志表。其余交给外部服务轮询处理。这个方案能解耦、可重试、可监控,也兼容主从延迟场景。
-
cache_key字段必须和应用层实际使用的 key 完全一致,比如应用读的是user:123,就不能写成USER:123或漏掉前缀 - 建表时推荐包含
created_at和status字段(值为pending/success/failed),便于排查失败任务 - 批量更新(如
UPDATE users SET status = 1 WHERE dept = 'tech')无法靠单条 key 失效覆盖,得提前在应用层维护集合类 key,例如users:dept:tech,再由轮询服务用SCAN+DEL清理
轮询服务怎么写才不丢 key、不重复删
轮询不是简单查表然后发 DEL,关键在锁控制、错误反馈和幂等性。
- 用
SELECT ... FOR UPDATE SKIP LOCKED读取status = 'pending'的行,避免多个进程争抢同一行 - 每次只处理少量行(比如 10–50 条),处理完立刻
DELETE或UPDATE status = 'success',别留“半完成”状态 -
DEL命令必须设socket_timeout=1,防止 Redis 响应慢拖死整个轮询周期 - 删除失败时,必须记录完整错误码(如
ConnectionError、Timeout),不能静默跳过;建议补一层EXISTS判断再删,避免重复操作误删其他 key
真正容易被忽略的是缓存 key 的设计本身
如果缓存 key 没按业务维度分组(比如用户 ID、部门、时间范围),光靠触发器逐条记录,永远跟不上批量变更节奏。同步失效的前提,是缓存结构能支撑“按需批量清理”。否则,轮询服务再稳,也只会陷入删不完、追不上的状态。

















