当前位置: 首页 > 科技观察

说说MySQL触发器

时间:2023-03-22 12:04:36 科技观察

本文转载自微信公众号“MySQL技术”,作者MySQL技术。转载本文请联系MySQL技术公众号。一、触发器简介触发器就是触发器,是与表相关的数据库对象。它们在满足定义的条件时被触发,并执行触发器中定义的语句集。它的执行不是由程序调用的,也不是手动启动的,而是由事件触发的,比如当对表进行操作(insert、delete、update)时,就会被激活执行。触发器通常用于强制执行数据完整性约束和业务规则。参考官方文档,触发器创建语法模板如下:只能用_trigger_name创建在永久表上,不能在临时表或视图上创建触发器。触发器名称在单个数据库中是唯一的。参考上面的创建语句,创建触发器有几个要素。这里简单说明一下:trigger_time:触发器动作时间,可以是BEFORE或AFTER,表示在每一行要修改之前或之后激活触发器。trigger_event:表示激活触发器的动作类型。这些trigger_event值是允许的:insert:只要有新行插入表中,触发器就会触发。例如插入、加载数据、替换语句。update:当表中的一行数据发生变化时激活触发器。例如更新语句。delete:当从表中删除一行数据时触发触发器。示例包括删除和替换语句。表上的DROPTABLE和TRUNCATETABLE语句不会激活此触发器,因为它们不使用删除,删除分区也不会激活删除触发器。trigger_body:是触发器被激活时要执行的语句。如果要执行多条语句,使用BEGIN…END复合语句结构。在triggerbody中,可以用old和new来指代trigger中发生变化的记录内容。2.触发器的具体操作我们来看触发器相关的具体操作:#Createtablecreatetriggermysql>CREATETABLEaccount(acct_numINT,amountDECIMAL(10,2));QueryOK,0rowsaffected(0.03sec)mysql>INSERTINTOaccountVALUES(137,14.98),(141,1937.50),(97,-100.00);mysql>delimiter//mysql>CREATETRIGGERupd_checkBEFOREUPDATEONaccountFOREACHROWBEGINIFNEW.amount<0THENSETNEW.amount=0;ELSEIFNEW.amount>100THENSETNEW.amountENDmy=;100;/sql/sql>delimiter;#验证触发函数mysql>select*fromaccount;+------------+--------+|acct_num|amount|+----------+---------+|137|14.98||141|1937.50||97|-100.00|+--------+--------+3rowsinset(0.00sec)mysql>updateaccountsetamount=114.98whereacct_num=137;QueryOK,1rowaffected(0.01sec)Rowmatched:1Changed:1Warnings:0mysql>select*fromaccount;+---------+----------+|acct_num|金额|+----------+--------+|137|100.00||141|1937.50||97|-100.00|+----------+--------+3rowsinset(0.00sec)#查看触发器mysql>showtriggers;#删除触发器mysql>droptriggerifexistsupd_check;#查看数据库实例中的所有触发器SELECTa.TRIGGER_SCHEMA,a.TRIGGER_NAME,a.ACTION_TIMING,a.EVENT_OBJECT_TABLE,a.EVENT_MANIPULATIONFROMinformation_schema.`TRIGGERS`aWHEREa.TRIGGER_SCHEMANOTIN('information_schema','performance_schema','mysql','sys');delimiter//设置MySQL执行结束标志,默认为;上面展示了关于触发器的一些基本操作,其实触发器在生产环境中是比较少见的,即使它可以解决我们的一些数据库需求,因为触发器的使用存在一系列的缺点,简单总结一下一些缺点如下:使用触发器实现的业务逻辑,出现问题时很难定位,尤其是涉及到多个触发器时,会给后期维护带来困难,从而增加了程序的复杂度。如果要改变的数据量很大,触发器的执行效率会很低。触发器的隐式调用很容易被忽略,问题很难排查。但触发器并非无用。例如,如果我们不希望人们删除或更新这张表中的数据,我们可以使用触发器。以下场景可能会给你启发:#Forbiddentodeletedataevenifyouhavepermissionmysql>select*fromstudent;+------------+------+---------+--------+-------+|increment_id|s_id|s_name|s_sex|s_age|+------------+------+--------+-------+--------+|1|1001|sdfsd|男|18||2|1003|zsdfsd|女|19|+------------+------+--------+--------+------+2rowsinset(0.00sec)mysql>delimiter//mysql>CREATETRIGGER`tri_delstu`BEFOREDELETEON`student`FOREACHROWbegin->declaremsgvarchar(255);->setmsg="不允许删除学生信息";->SIGNALSQLSTATE'HY000'SETMESSAGE_TEXT=msg;->end;//QueryOK,0rowsaffected(0.02sec)mysql>delimiter;mysql>deletefromstudentwheres_id=1003;ERROR1644(HY000):不允许删除学生信息#禁止更新一个字段mysql>delimiter//mysql>CREATETRIGGERtrg__updateSidBEFOREUPDATEON`student`->FOREACHROW->BEGIN->DECLAREmsgVARCHAR(100);->IFNEW.s_id<>OLD.s_idTHEN->SETmsg='不允许修改学号';->SIGNALSQLSTATE'HY000'SETmessage_text=msg;->ENDIF;->END;//QueryOK,0rowsaffected(0.06sec)mysql>delimiter;mysql>updatestudentsets_id=1002whereincrement_id=2;ERROR1644(HY000):不允许修改学号#limit修改范围mysql>delimiter//mysql>CREATETRIGGER`tri_update_age`BEFOREUPDATEON`student`FOREACHROWBEGIN->DECLAREmsgVARCHAR(20);->IF(NEW.s_age<0)THEN->setmsg="agecannotbelessthan0";->signalsqlstate'HY000'setmessage_text=msg;->ENDIF;->END;//QueryOK,0rowsaffected(0.02sec)mysql>delimiter;mysql>updatestudentsets_age=10wheres_id=1001;QueryOK,1rowaffected(0.01sec)Rowsmatched:1Changed:1Warnings:0mysql>updatestudentsets_age=-10wheres_id=1001;ERROR1644(HY000):年龄不能小于0:本文简介在业务逻辑复杂或表变化频繁的系统中,不建议使用触发器的定义和用例。当然,它也有自己的应用场景。不管怎样,触发器的逻辑总是越简单越好。我们应该让数据库做它擅长的事情,你不能认为所有的逻辑都在数据库层面实现。