MySQL触发器无法直接操作Redis,因二者隔离且MySQL原生不支持外部命令;推荐方案是监听binlog由外部消费者同步,或应用层事务后主动刷新缓存。

MySQL 触发器本身不能直接操作 Redis
触发器运行在 MySQL 服务端,而 Redis 是独立进程,MySQL 原生不提供网络 I/O 或外部命令执行能力(sys_exec 等 UDF 属于非安全扩展,且默认禁用)。所以你写 AFTER UPDATE 触发器里直接调 redis-cli SET 是无效的——MySQL 不认识这条命令,也不会执行。
UDF 方案风险高、维护难、多数生产环境禁用
虽然存在如 lib_mysqludf_sys 这类允许执行系统命令的 UDF,但实际落地有硬伤:
-
sys_exec需要 MySQL 启动时加--secure-file-priv=为空或显式放开,这违反最小权限原则 - Redis 写入失败无重试、无日志、无超时控制,缓存会静默丢失
- UDF 编译依赖 MySQL 源码版本,升级 MySQL 很可能崩溃或失效
- 主流云数据库(如阿里云 RDS、腾讯云 CDB)明确禁止安装自定义 UDF
简单示例(不推荐):
CREATE FUNCTION redis_set RETURNS STRING SONAME 'lib_mysqludf_sys.so';之后在触发器里写
SELECT redis_set(CONCAT('redis-cli -h 127.0.0.1 SET user:', NEW.id, ' ', NEW.name)); —— 看似可行,实则不可靠。
更可行的实时同步路径:用 binlog + 外部消费者
真正被大规模验证的方案是绕过触发器,监听 MySQL 的 binlog,由外部服务解析并刷新 Redis。关键点:
- MySQL 必须开启
binlog_format = ROW和binlog_row_image = FULL - 使用
canal(阿里)、maxwell(Zendesk)或debezium(Red Hat)捕获变更事件 - 消费者程序(Go/Python/Java)收到
UPDATE user SET name='xxx' WHERE id=123后,构造SET user:123 "xxx"写入 Redis - 可加入幂等判断(如用
DEL+SET替代单纯SET)、失败重试队列、延迟双删逻辑
比如 maxwell 输出 JSON:
{"database":"test","table":"user","type":"update","data":{"id":123,"name":"alice"}}你的消费脚本就能精准提取字段更新缓存。
如果非要“触发器+Redis”,只能走中间代理层
极少数场景下,可让触发器写一条记录到本地 cache_sync_log 表,再由一个定时任务(如每秒查一次)读取并推送 Redis。但这不是实时,而是准实时(延迟 ≤ 1s),且引入额外表和轮询开销。
- 触发器只做
INSERT INTO cache_sync_log (table_name, pk, op) VALUES ('user', NEW.id, 'UPDATE'); - 外部脚本用
SELECT ... FOR UPDATE SKIP LOCKED安全消费,避免重复处理 - 必须加索引:
CREATE INDEX idx_pending ON cache_sync_log (status, created_at) WHERE status = 'pending';
这种折中方式规避了 UDF 和 binlog 权限问题,但吞吐量低、状态管理复杂,仅适合低频更新的小型系统。
真正卡住的不是技术选型,而是对“实时”的定义——如果你的业务能接受 100ms 级别的延迟,binlog 消费是最稳的;如果连 1 秒都不能等,那该考虑是不是把缓存逻辑收归应用层,让 ORM 或 DAO 在事务提交后主动刷 Redis,而不是强求数据库替你完成跨系统协作。


















