千家信息网

记一次由mysql触发器引发的故障

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,上周六到公司上班,刚坐下没多久,公司业务传过消息说,用户borrow表信息无法更新。查看网站报错如下:报错信息表示是由于mysql的函数和触发器引起的,问了下公司开发,他们表示函数功能已经测试上线好久
千家信息网最后更新 2026年11月03日记一次由mysql触发器引发的故障

上周六到公司上班,刚坐下没多久,公司业务传过消息说,用户borrow表信息无法更新。查看网站报错如下:

报错信息表示是由于mysql的函数和触发器引起的,问了下公司开发,他们表示函数功能已经测试上线好久了,没有问题,而触发器是这周刚上的。于是,赶紧进入生产的DB服务器进行查看:

mysql> use wendi;Database changedmysql> SHOW TRIGGERS\G;...*************************** 2. row ***************************             Trigger: cl_borrow_before_insert_tigger               Event: INSERT               Table: cl_borrow           Statement: begin  set @channel_id = (select channel_id from cl_user where user_id = new.user_id);  -- if @channel_id is not null and new.channel_id is null THEN  --   update cl_borrow set channel_id=@channel_id where borrow_id = new.borrow_id;  -- end if;  insert into cl_borrow_status_log (user_id,borrow_id,status_old,status_new,audit_user_id,audit_remark,create_time,channel_id) values (new.user_id,new.borrow_id,null,new.status,new.audit_user_id,new.audit_remark,UNIX_TIMESTAMP(now()),@channel_id);end              Timing: BEFORE             Created: NULL            sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION             Definer: root@%character_set_client: utf8collation_connection: utf8_general_ci  Database Collation: utf8_general_ci*************************** 3. row ***************************             Trigger: cl_borrow_after_insert_trigger               Event: INSERT               Table: cl_borrow           Statement: begin  set @channel_id = (select channel_id from cl_user where user_id = new.user_id);  -- if @channel_id is not null and new.channel_id is null THEN  --   update cl_borrow set channel_id=@channel_id where borrow_id = new.borrow_id;  -- end if;  insert into cl_borrow_status_log (user_id,borrow_id,status_old,status_new,audit_user_id,audit_remark,create_time,channel_id) values (new.user_id,new.borrow_id,null,new.status,new.audit_user_id,new.audit_remark,UNIX_TIMESTAMP(now()),@channel_id);end              Timing: AFTER             Created: NULL            sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION             Definer: root@%character_set_client: utf8collation_connection: utf8_general_ci  Database Collation: utf8_general_ci*************************** 4. row ***************************             Trigger: cl_borrow_after_update_trigger               Event: UPDATE               Table: cl_borrow           Statement: begin  if old.status != new.status then     set @channel_id = (select channel_id from cl_user where user_id = new.user_id);     insert into cl_borrow_status_log (user_id,borrow_id,status_old,status_new,audit_user_id,audit_remark,create_time,channel_id) values (new.user_id,new.borrow_id,old.status,new.status,new.audit_user_id,new.audit_remark,UNIX_TIMESTAMP(now()),@channel_id);  end if;end              Timing: AFTER             Created: NULL            sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION             Definer: root@%character_set_client: utf8collation_connection: utf8_general_ci  Database Collation: utf8_general_ci*************************** 5. row ***************************             Trigger: cl_borrow_status_log               Event: INSERT               Table: cl_borrow_status_log           Statement: BEGIN  update cl_borrow set double_audit_user_id = new.audit_user_id,double_audit_time=new.create_time where borrow_id=new.borrow_id ;end              Timing: AFTER             Created: NULL            sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION             Definer: root@%character_set_client: utf8collation_connection: utf8_general_ci  Database Collation: utf8_general_ci    ...    11 rows in set (0.00 sec)

如上,总共有11条触发器。为了不影响业务,我决定先将触发器备份,然后将其删除。

1,备份mysql触发器:
mysqldump --triggers -R -ndt -uroot -p cashloan> wenditrigger.sql

这里复习下mysqldump命令:

--triggers: Dump triggers for each dumped table. (Defaults to on; use --skip-triggers to disable.)

这个是默认值,mysqldump默认会导出触发器。(如果不想备份触发器使用--skip-triggers即可)

-R, --routines: Dump stored routines (functions and procedures).

导出存储过程以及函数。

-n, --no-create-db Suppress the CREATE DATABASE ... IF EXISTS statement that normally is output for each dumped database if --all-databases or --databases is given.

不创建建库语句,只对数据进行导出。

-d, --no-data No row information.

不导出数据,只导出表结构。

-t, --no-create-info Don't write table creation info.

不导出建表语句,只导出数据。

2,查看备份内容:
[root@DB ~]$ less wenditrigger.sql-- MySQL dump 10.13  Distrib 5.6.20, for linux-glibc2.5 (x86_64)...DELIMITER ;;/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`%`*/ /*!50003 TRIGGER `__test_trigger_update` AFTER INSERT ON `__test` FOR EACH ROW begin  if new.user_id=100 THEN    update __test set tian='@@@@' where id=new.id;  end if;  insert into __test2 (id,tian,user_id) values (new.id,new.tian,new.user_id);end */;;.../*!50003 CREATE*/ /*!50017 DEFINER=`root`@`%`*/ /*!50003 TRIGGER `cl_borrow_before_insert_tigger` BEFORE INSERT ON `cl_borrow` FOR EACH ROW begin  set @channel_id = (select channel_id from cl_user where user_id = new.user_id);  -- if @channel_id is not null and new.channel_id is null THEN  --   update cl_borrow set channel_id=@channel_id where borrow_id = new.borrow_id;  -- end if;  insert into cl_borrow_status_log (user_id,borrow_id,status_old,status_new,audit_user_id,audit_remark,create_time,channel_id) values (new.user_id,new.borrow_id,null,new.status,new.audit_user_id,new.audit_remark,UNIX_TIMESTAMP(now()),@channel_id);end */;;DELIMITER ;

可以看到触发器已经备份好了。

3,删除触发器:

因为当时情况紧急,首要任务是将业务恢复,所以就把触发器全部删除了。
删除暂时没找到批量的方法,还好数据只有11条,一条一条删吧。

...mysql> drop trigger cl_borrow_after_insert_trigger;mysql> drop trigger cl_borrow_after_update_trigger;mysql> drop trigger cl_borrow_status_log;mysql> drop trigger cl_installment_after_insert_trigger;...

至此,业务终于恢复了。

小结:

1,MySQL触发器属于隐式调用,往往会在你不知道的情况下做出许多操作,从而增加系统的复杂程度。
2,复杂MySQL触发器会嵌套使用,这就有可能产生死锁,本例就是个印证,borrow表触发插入其他表,而插入其他表的操作又会触发borrow表更新,这就产生了死锁,导致borrow表无法被更新。

MySQL触发器简介:

触发器是一种与表操作有关的数据库对象,当触发器所在表上出现指定事件时,将调用该对象,即表的操作事件触发表上的触发器的执行。
触发器语法:

CREATE TRIGGER trigger_nametrigger_timetrigger_event ON table_nameFOR EACH ROWtrigger_statement

trigger_name:触发器名称
trigger_time:触发器触发时机(BEFORE/AFTER)
trigger_event: 触发事件(INSERT,UPDATE,DELETE)
table_name: 建立触发器的表名称
trigger_statement: 触发器程序体,可以为单一的SQL语句,也可以是包含BEGIN,END在内的多条语句。
FOR EACH ROW: 行级触发

参考文章:
https://www.cnblogs.com/duodushu/p/5446384.html

触发器 备份 数据 业务 语句 事件 公司 函数 更新 复杂 信息 名称 对象 情况 死锁 任务 内容 功能 只有 命令 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 金诺互联网科技 华宇互联网科技 远拓互联网科技 互联网科技小额贷款 互联网科技股有哪些 汉立互联网科技有限公司联系电话 卫星互联网科技股票 济南华为互联网科技产业总部基地 玉溪互联网科技怎么选 注册互联网科技公司经营范围大全 河南住房之家互联网科技 美国互联网科技实力 宇信科技在杭州互联网排第几 下一代互联网重大应用科技园 保山互联网科技靠谱吗 科技互联网专业工作会议发言稿 承德科技产业互联网平台 网互联网络科技 科技互联网企业在行动 如何强化互联网金融科技 苏州找大状互联网科技有限公司 智能科技公司是互联网公司吗 融势互联网科技 撒么互联网科技公司 深圳卡尔迅互联网科技有限公司怎么样 西藏七维空间互联网科技有限公司 互联网媒体平台算高科技产业 哈尔滨屹滨互联网科技有限公司 黑科技 体验场景 互联网大会 美国互联网科技公司
0