mysql如何临时禁用触发器

起因

Mysql的触发器,在触发控制上,只能按照对数据的操作方式(Insert,Update,Delete)以及操作前后(before,after)进行触发控制。但是如果碰到以下需求又该如何:对于A表的Insert语句,只有符合某些条件的数据触发Insert触发器。

自己当初条件反射的写法

在对应的触发器语句中,增加条件判断的逻辑。举个栗子:

有个用户信息表user,有个通讯录表addressbook,两张表表结构类似,业务需求上某些数据需要做数据实时同步,即user有更新,addressbook也要更新。用户表有个Insert触发器,只把性别为男的用户数据插入到addressbook中。

两表结构如下:

#为方便起见两个表结构就一模一样了,真实环境下一般都是部分字段类似而已

#性别字段取值1男0女

CREATE TABLE `user` (

`id` INT(11) NOT NULL AUTO_INCREMENT,

`name` VARCHAR(50) NULL DEFAULT NULL,

`sex` TINYINT(4) NULL DEFAULT '0',

`age` INT(11) NULL DEFAULT '0',

`phone` VARCHAR(50) NULL DEFAULT NULL,

`qq` VARCHAR(50) NULL DEFAULT NULL,

PRIMARY KEY (`id`)

)

;

CREATE TABLE `addressbook` (

`id` INT(11) NOT NULL AUTO_INCREMENT,

`name` VARCHAR(50) NULL DEFAULT NULL,

`sex` TINYINT(4) NULL DEFAULT '0',

`age` INT(11) NULL DEFAULT '0',

`phone` VARCHAR(50) NULL DEFAULT NULL,

`qq` VARCHAR(50) NULL DEFAULT NULL,

PRIMARY KEY (`id`)

)

;

此时user表的Insert触发器写法:

CREATE DEFINER=`root`@`localhost` TRIGGER `user_insert_trigger` BEFORE INSERT ON `user` FOR EACH ROW

BEGIN

if new.sex = 1

then

insert into addressbook (name,sex,age,qq,phone)

values (new.name,new.sex,new.age,new.qq,new.phone)

;

end if;

END

经常码代码的程序猿们,应该最先想到的是这种写法吧,毕竟符合咱们平常写代码的逻辑。但是需求往往不是那么简单的,这头怪兽总是会向着我们不可预期的方向发展。再举个栗子:

现在只要同步这些用户:年龄大于30岁,qq号小于8位的,使用189手机的男用户。(卧槽(╯‵□′)╯︵┻━┻)。现在的触发器语句可能是这样子:

CREATE DEFINER=`root`@`localhost` TRIGGER `user_insert_trigger` BEFORE INSERT ON `user` FOR EACH ROW BEGIN

if new.sex = 1 and substring(new.phone,1,3)=189 and length(new.qq) <=8 and new.age >30

then

insert into addressbook (name,sex,age,qq,phone)

values (new.name,new.sex,new.age,new.qq,new.phone)

;

end if;

END

不就是if多了几个and条件,多使用了几个sql函数而已嘛!这的是这样吗?如果手机的判断条件变成是“福建电信用户”(不止是189号头哦)呢?还有更奇葩的需求:如果要实现user表和addressbook表双向同步怎么办,没错,就是user表跟addressbook表都有insert触发器往对方表插数据,这在mysql下是不允许的(防止循环触发)。当时碰到这个需求我竟然脑袋一热也用上面的方法这么写,触发器插入前判断new的数据在要插入的表里存不存在orz。

总结一下,上面的触发器写法有很多缺点:

当对触发的数据有过滤需求时,需要用数据库语言写很多条件判断语句,有些在程序语言中很好实现的,在数据库语言中非常困难。

不利于理解与维护。由于有了1中那么多逻辑判断代码,导致触发器的语句会很冗长且复杂,阅读起来非常困难,即使加了注释。

不利于调试。数据库语言毕竟不像其他程序设计语言,你想打断点或者输出日志看是什么原因没有触发吗?图样,只能将insert数据插入到一张临时表里查看。

如果两张表有互相insert触发往对方表增加新数据的逻辑,这种写法要么不可行,要么作死。

更灵活优雅的写法

方法是使用mysql的session级变量控制触发器触发,然后把上面的一堆判断逻辑放到程序代码中。这是在google上找到的stackoverflow帖子,感觉挺有用的。

举个栗子,上面的触发器可以这么写:

CREATE DEFINER=`root`@`localhost` TRIGGER `user_insert_trigger` BEFORE INSERT ON `user` FOR EACH ROW

#这里@disable_triggers 是自定义的session变量(mysql中约定session变量用@开头,只对某一次会话有效,不影响其他会话),保证使用时各个触发器名字不一样就好

BEGIN

IF @disable_triggers IS NULL THEN

insert into addressbook (name,sex,age,qq,phone)

values (new.name,new.sex,new.age,new.qq,new.phone)

;

END IF;

END

如果在使用insert语句时,不想触发触发器,在sql语句前后加上这么两句即可。

#变量设为非NULL,这样不会进入触发器的相关操作

SET @disable_triggers = 1;

#不打算触发触发器的insert语句

insert into user values(....);

#上面语句执行完毕完毕后,重新将变量设置为NULL,重新开启触发逻辑

SET @disable_triggers = NULL;

对于某些更新数据时暂时想禁用触发器的情况,这种方法就可以先在程序代码中实现判断,然后决定要不要在执行的sql语句前后加入SET @disable_triggers = 1; 和 SET @disable_triggers = NULL; 来临时禁止触发器触发操作,触发器的代码就可以做到非常简洁而且容易维护。将判断逻辑放到程序代码中也方便debug。

不过在实践中发现此方法要注意以下几点(我使用的开发语言为java):

SET @disable_triggers = 1; SET @disable_triggers = NULL; 这两个语句必须与要执行的sql放在同一条sql中,然后一起提交执行。不能先 执行 SET @disable_triggers = 1; 再执行数据更新语句,再执行SET @disable_triggers = NULL; ,因为使用的变量是session变量,只有在同一个会话中,触发器才能找到disable_triggers变量。如果分成三次提交执行,相当于三个会话,触发器那边得到的disable_triggers变量还是为NULL。

对于java中的 sql prepared statement 预处理执行sql语句的方式,以上设置session变量的方法会抛异常。(预处理模式不支持一次同时提交多个sql语句?)我在项目中使用的是spring 的jdbctemplate,原生jdbc应该也是一样的。所以使用这种方法临时禁用触发器时,还是老实做好参数防注入判断,然后拼接sql语句执行吧,还好这种需求的场景不会很多。

mysql暂停触发器_mysql如何临时禁用触发器相关推荐

  1. mysql命令行查看表的触发器_Mysql事项,视图,函数,触发器命令(详解)

    事项开启和使用 //修改表的引擎 alter table a engine=myisam; //开启事务 begin; //关闭自动提交 set autocommit=0; //扣100 update ...

  2. mysql自定义存储过程_MySQL自定义函数、触发器、存储过程

    存储过程 概念 存储过程,是一个数据库对象,类似一个函数. 在存储过程中可以使用SQL中的绝大部分内容,并且可以加入编程语言的特性(循环判断分支). 编写好存储过程之后,可以在客户端调用存储过程,存储 ...

  3. mysql启动触发器_MYSQL中禁用/启动触发器

    在使用MYSQL过程中,经常会使用到触发器,但是有时使用不当会造成一些麻烦.有没有一种办法可以控制触发器的调用呢? 触发器顾名思义就是数据库在一定的调条件自动调用的SQL语句,触发器拒绝了人工调用的过 ...

  4. mysql delete语句_MySQL ------ 触发器(TRIGGER)(二十七)

    MySQL 语句在需要时被执行,存储过程也是,但是你要是想要某条(或某些语句)在事件发生时自动执行,该怎么办触发器由此而来 触发器:某个表发生更改时自动处理.触发器是MySQL响应delete,ins ...

  5. mysql级联删除_MySQL进阶三板斧(三)看清“触发器 (Trigger)”的真实面目

    触发器(Trigger)的起源 MySQL是最受欢迎的开源RDBMS,被社区和企业广泛使用.触发器是MySQL在5.0.1(开天辟地一版本)中增加的三大新功能之一,另外两个师兄弟是视图(view)与存 ...

  6. mysql 索引触发_Mysql基本查询、视图、索引、触发器

    基本查询 1.修改 String sql="update smbms_user set userCode=?,userName=? where id=?"; 2.删除用户 Stri ...

  7. mysql latid1_【转】mysql触发器的实战经验(触发器执行失败,sql会回滚吗) | 学步园...

    1   引言Mysql的触发器和存储过程一样,都是嵌入到mysql的一段程序.触发器是mysql5新增的功能,目前线上凤巢系统.北斗系统以及哥伦布系统使用的数据库均是mysql5.0.45版本,很多程 ...

  8. 删除trigger 禁用触发器 启用触发器 查看触发器

    删除trigger drop trigger 触发器名 on 在那个表上 禁用触发器 Alter Table 表名 disable trigger 触发器名 启用触发器 Alter Table 表名 ...

  9. mysql数据库、表、索引、触发器

    ctrl +c退出sql程序 1.数据库 查看数据库:show databases: 创建数据库:create database tb_name; 删除数据库:drop database db_nam ...

最新文章

  1. Ubuntu 14.04环境变量修改
  2. Redis 之(二) Redis的基本数据结构以及一些常用的操作
  3. arm架构的linux芯片方案,ARM推64位处理器架构ARMV8及芯片[多图]
  4. 计算机电子与网络技术,电子信息工程与计算机网络技术
  5. 永远不会执行的cron表达式
  6. 计算机应用技术环境评估,计算机应用教程(第7版)(Windows 7与Office 2007环境)习题解答与上机练习...
  7. Idea怎么实现画类图
  8. 【matlab】找出数组中符合条件的数并赋值
  9. 关于TCP三次握手过程
  10. 必成功的Hadoop环境搭建jdk环境搭建-超详细操作
  11. 【Go语言】深入浅出chan(各种实例场景+分析)
  12. 基于飞桨实现高光谱影像和全色影像融合
  13. PC和开发板之间传输文件
  14. 数据可视化实验:python数据可视化-柱状图,条形图,直方图,饼图,棒图,散点图,气泡图,雷达图,箱线图,折线图
  15. 闻与MyBatis之MyBatis快速指南
  16. Pytorch——如何创建一个tensor与索引和切片(一)
  17. python读文件夹图片,做数据集
  18. LeetCode P104--二叉树的最大深度
  19. java 使用sourceforge.pinyin4j查询汉字拼音
  20. Linux 内核编程指南

热门文章

  1. JavaScript中几个优雅的运算符使用技巧
  2. Serverless Devs 的官网是如何通过 Serverless Devs 部署的?
  3. AI技术已达如此高度:去码、上色6到飞起
  4. 调度算法为何被阿里如此重视?
  5. 如何用智能有效感知城市?城市大脑三大AI产品来了
  6. 处理增删改_这10个批量处理的PPT技巧,让你的效率提升100倍!
  7. 用科幻艺术描绘未知的魅力-人物篇
  8. 开发笔记:掉落系统模块设计思路
  9. Unity 高清渲染管线 ShaderGraph 实现简单的表面水流效果
  10. CSDN创始人蒋涛:拥抱中国开源技术生态发展黄金十年