MySQL触发器嵌套问题:删除父表仅需回收站单条记录
问题分析
当前删除父表时,父表触发器会批量更新所有关联子表的is_deleted字段,每一条子表的更新都会触发子表触发器向sn_recycle插入一条子表记录,再加上父表自身插入的记录,导致回收站生成多条冗余记录。核心需求是:父表删除时仅保留父表对应的回收站记录,子表仅在单独被删除时生成回收站记录。
解决方案
通过会话变量控制子表触发器的执行逻辑,区分父表触发的批量更新和子表单独删除的场景:
1. 修改父表触发器
在批量更新子表前设置会话变量,标记当前操作来自父表删除触发,操作完成后重置变量:
DROP TRIGGER IF EXISTS `after_recorditems_update`; CREATE DEFINER=`root`@`localhost` TRIGGER `after_recorditems_update` AFTER UPDATE ON `sn_recorditems` FOR EACH ROW BEGIN -- 标记当前为父表触发的子表批量更新 SET @PARENT_DELETE_TRIGGER = 1; -- 更新关联子表的删除状态 UPDATE sn_recordlog SET is_deleted = new.is_deleted WHERE new.id = `recordid`; -- 插入父表回收站记录,关联所有子表的log_id INSERT INTO sn_recycle(deleted_at,recorditem_id,log_id,from_table_name) VALUES( new.time, new.id, (SELECT GROUP_CONCAT(sn_recordlog.id SEPARATOR ', ') FROM sn_recordlog WHERE new.time = sn_recordlog.time), 'sn_recorditems' ); -- 重置会话变量,不影响后续操作 SET @PARENT_DELETE_TRIGGER = NULL; END
2. 修改子表触发器
增加会话变量判断,仅当不是父表触发的更新时,才插入子表的回收站记录:
DROP TRIGGER IF EXISTS `after_recordlog_update`; CREATE DEFINER=`root`@`localhost` TRIGGER `after_recordlog_update` AFTER UPDATE ON `sn_recordlog` FOR EACH ROW BEGIN -- 仅在单独删除子表时执行插入 IF @PARENT_DELETE_TRIGGER IS NULL THEN INSERT INTO sn_recycle(deleted_at,recorditem_id,log_id,from_table) VALUES(new.time, new.recordid, new.id, 'sn_recordlog'); END IF; END
验证逻辑
- 单独删除子表:手动设置子表
is_deleted=1时,会话变量不存在,子表触发器正常插入回收站记录。 - 删除父表:父表触发器先标记会话变量,批量更新子表时,子表触发器检测到变量存在,跳过插入操作,仅父表触发器插入一条关联所有子表的回收站记录,完全符合需求。
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

