作者:mysqlAB;翻译:陈朋奕
ConventionsandStyles约定和编程风格 财软联盟,fs119.net
每次我想要演示实际代码时,我会对mysql客户端的屏幕就出现的代码进行调整,将
mysql>DROPFUNCTIONf;
QueryOK,0rowsaffected(0.00sec) 财软 联盟 fs119.net
如果实例比较大,则需要在某些行和段落间加注释,同时我会用将"<--"符号放在页面的右边以表示强调。例如:
财管家.园.fs119.net
mysql>CREATEPROCEDUREp()
->BEGIN
->/*Thisproceduredoesnothing*/<--
->END;//
QueryOK,0rowsaffected(0.00sec) 财.管家园.fs119.net
有时候我会将例子中的"mysql>"和"->"这些系统显示去掉,你可以直接将代码复制到mysql客户端程序中(如果你现在所读的不是电子版的,可以在mysql.com网站下载相关脚本)
财管家.园.fs119.net
所以的例子都已经在Suse9.2
WhyTriggers为什么要用触发器 财,软联盟,fs119.net
我们在MySQL5.0中包含对触发器的支持是由于以下原因: 财 软联盟 fs119.net
MySQL早期版本的用户长期有需要触发器的要求。
我们曾经许诺支持所有ANSI标准的特性。
您可以使用它来检查或预防坏的数据进入
您可以改变或者取消INSERT,UPDATE以及DELETE语句。
您可以在一个会话中监视数据改变的动作。
在这里我假定大家都读过"MySQL新特性"丛书的第一集--"MySQL存储过程",那么大家都应该知道MySQL至此存储过程和函数,那是很重要的知识,因为在触发器中你可以使用在函数中使用的语句。特别举个例子: 财管家园,fs119.net
复合语句(BEGIN/END)是合法的.
财软.联盟.fs119.net
流控制(Flow-of-control)语句(IF,CASE,WHILE,LOOP,WHILE,REPEAT,LEAVE,ITERATE)也是合法的. 财管家园,fs119.net
变量声明(DECLARE)以及指派(SET)是合法的. 财.管家园.fs119.net
允许条件声明. 财软联,盟,fs119.net
异常处理声明也是允许的.
但是在这里要记住函数有受限条件:不能在函数中访问表.因此在函数中使用以下语句是非法的。
财,软联盟,fs119.net
ALTER'CACHEINDEX'CALLCOMMITCREATEDELETE 财软联 盟 fs119.net
DROP'FLUSHPRIVILEGES'GRANTINSERTKILL 财软联盟,fs119.net
LOCKOPTIMIZEREPAIRREPLACEREVOKE 财.软联盟.fs119.net
ROLLBACKSAVEPOINT'SELECTFROMtable'
财软,联盟,fs119.net
'SETsystemvariable''SETTRANSACTION' 财软 联盟 fs119.net
SHOW'STARTTRANSACTION'TRUNCATEUPDATE
财软,联盟,fs119.net
在触发器中也有完全一样的限制.
触发器相对而言比较新,因此会有(bugs)缺陷.所以我在这里给大家警告,就像我在存储过程书中所说那样.不要在含有重要数据的数据库中使用这个触发器,如果需要的话在一些以测试为目的的数据库上使用,同时在你对表创建触发器时确认这些数据库是默认的。
财管.家园.fs119.net
Syntax语法
1.Syntax:Name语法:命名规则 财软,联盟,fs119.net
CREATETRIGGER<触发器名称><--
{BEFORE|AFTER}
{INSERT|UPDATE|DELETE}
ON<表名称>
FOREACHROW
<触发器SQL语句> 财管家.园.fs119.net
触发器必须有名字,最多64个字符,可能后面会附有分隔符.它和MySQL中其他对象的命名方式基本相象. 财软联盟 fs119.net
这里我有个习惯:就是用表的名字+'_'+触发器类型的缩写.因此如果是表t26,触发器是在事件UPDATE(参考下面的点(2)和(3))之前(BEFORE)的,那么它的名字就是t26_bu。 财管家园 fs119.net
2.Syntax:Time语法:触发时间 财 软联盟 fs119.net
CREATETRIGGER<触发器名称>
{BEFORE|AFTER}<--
{INSERT|UPDATE|DELETE}
ON<表名称>
FOREACHROW
<触发的SQL语句>
触发器有执行的时间设置:可以设置为事件发生前或后。 财软联盟,fs119.net
3.Syntax:Event语法:事件
CREATETRIGGER<触发器名称>
{BEFORE|AFTER}
{INSERT|UPDATE|DELETE}<--
ON<表名称>
FOREACHROW
<触发的SQL语句>
财软联盟,fs119.net
同样也能设定触发的事件:它们可以在执行insert、update或delete的过程中触发。 财 软联盟 fs119.net
4.Syntax:Table语法:表 财管家,园,fs119.net
CREATETRIGGER<触发器名称>
{BEFORE|AFTER}
{INSERT|UPDATE|DELETE}
ON<表名称><--
FOREACHROW
<触发的SQL语句>
触发器是属于某一个表的:当在这个表上执行插入、更新或删除操作的时候就导致触发器的激活.
我们不能给同一张表的同一个事件安排两个触发器。 财软联 盟 fs119.net
5.Syntax:Granularity语法:(:(步长)触发间隔
CREATETRIGGER<触发器名称>
{BEFORE|AFTER}
{INSERT|UPDATE|DELETE}
ON<表名称>
FOREACHROW<--
<触发的SQL语句> 财管.家园.fs119.net
触发器的执行间隔:FOREACHROW子句通知触发器每隔一行执行一次动作,而不是对整个表执行一次。 财 软联盟 fs119.net
6.Syntax:Statement语法:语句
财,管家园,fs119.net
CREATETRIGGER<触发器名称>
{BEFORE|AFTER}
{INSERT|UPDATE|DELETE}
ON<表名称>
FOREACHROW
<触发的SQL语句><--
财管 家园 fs119.net
触发器包含所要触发的SQL语句:这里的语句可以是任何合法的语句,包括复合语句,但是这里的语句受的限制和函数的一样。 财管家.园.fs119.net
Privileges权限 财管家园,fs119.net
你必须拥有相当大的权限才能创建触发器(CREATETRIGGER)。如果你已经是Root用户,那么就足够了。这跟SQL的标准有所不同,我也希望能尽快改成标准的。 财软联 盟 fs119.net
因此在下一个版本的MySQL中,你完全有可能看到有一种叫做CREATETRIGGER的新权限。然后通过这样的方法赋予:
财管家园 fs119.net
GRANTCREATETRIGGERON<表名称>TO<用户或用户列表>; 财软.联盟.fs119.net
也可以通过这样收回权限: 财管家,园,fs119.net
REVOKECREATETRIGGERON<表名称>FROM<用户或用户列表>;
ReferringtoOLDandNEWcolumns关于旧的和新创建的列的标识
在触发器的SQL语句中,你可以关联表中的任意列。但你不能仅使用列的名称去标识,那会使系统混淆,因为那里可能会有列的新名(这可能正是你要修改的,你的动作可能正是要修改列名),还有列的旧名存在。因此你必须用这样的语法来标识: 财软 联盟 fs119.net
"NEW.column_name"或者"OLD.column_name".这样在技术上处理(NEW|OLD.column_name)新和旧的列名属于创建了过渡变量("transitionvariables")。 财软 联盟 fs119.net
对于INSERT语句,只有NEW是合法的;对于DELETE语句,只有OLD才合法;而UPDATE语句可以在和NEW以及OLD同时使用。下面是一个UPDATE中同时使用NEW和OLD的例子。 财管 家园 fs119.net
CREATETRIGGERt21_au
BEFOREUPDATEONt22
FOREACHROW
BEGIN
SET@old=OLD.s1;
SET@new=NEW.s1;
END;// 财管家园,fs119.net
现在如果t21表中的s1列的值是55,那么执行了"UPDATEt21SETs1=s1+1"之后@old的值会变成55,而@new的值将会变成56。 财软,联盟,fs119.net
ExampleofCREATEandINSERTCREATE和INSERT的例子
财管家.园.fs119.net
CREATEtablewithtrigger创建有触发器的表 财软联.盟.fs119.net
这里所有的例程中我都假定大家的分隔符已经设置成//(DELIMITER//)。
CREATETABLEt22(s1INTEGER)// 财软联盟 fs119.net
CREATETRIGGERt22_bi
BEFOREINSERTONt22
FOREACHROW
BEGIN
SET@x='Triggerwasactivated!';
SETNEW.s1=55;
END;// 财 管家园 fs119.net
在最开始我创建了一个名字为t22的表,然后在表t22上创建了一个触发器t22_bi,当我们要向表中的行插入时,触发器就会被激活,执行将s1列的值改为55的动作。
财管家园,fs119.net
INSERTontablewithatrigger使用触发器执行插入动作 财软联盟 fs119.net
mysql>INSERTINTOt22VALUES(1)//
让我们看如果向表t2中插入一行数据触发器对应的表会怎么样?
这里的插入的动作是很常见的,我们不需要触发器的权限来执行它。甚至不需要知道是否有触发器关联。 财软联盟.fs119.net
mysql>SELECT@x,t22.*FROMt22//
+------------------------+------+
|@x|s1|
+------------------------+------+
|Triggerwasactivated!|55|
+------------------------+------+
1rowinset(0.00sec) 财软联盟,fs119.net
大家可以看到INSERT动作之后的结果,和我们预期的一样,x标记被改动了,同时这里插入的数据不是我们开始输入的插入数据,而是触发器自己的数据。
财软联 盟 fs119.net
Exampleofa"check"constraint
"check"完整性约束例子 财软.联盟.fs119.net
What'sa"check"constraint什么是"check"约束 财,软联盟,fs119.net
在标准的SQL语言中,我们可以在(CREATETABLE)创建表的过程中使用"CHECK(condition)",
例如:
财 管家园 fs119.net
CREATETABLEt25
(s1INT,s2CHAR(5),PRIMARYKEY(s1),
CHECK(LEFT(s2,1)='A'))
ENGINE=INNODB;
财软联,盟,fs119.net
这里CHECK的意思是"当s2列的最左边的字符不是'A'时,insert和update语句都会非法",MySQL的视图不支持CHECK,我个人是很希望它能支持的。但如果你很需要在表中使用这样的功能,我建议大家使用触发器来实现。 财管家园.fs119.net
CREATETABLEt25
(s1INT,s2CHAR(5),
PRIMARYKEY(s1))
ENGINE=INNODB//
CREATETRIGGERt25_bi
BEFOREINSERTONt25
FOREACHROW
IFLEFT(NEW.s2,1)<>'A'THENSETNEW.s1=0;ENDIF;//
CREATETRIGGERt25_bu
BEFOREUPDATEONt25
FOREACHROW
IFLEFT(NEW.s2,1)<>'A'THENSETNEW.s1=0;ENDIF;//
我只需要使用BEFOREINSERT和BEFOREUPDATE语句就行了,删除了触发器不会对表有影响,同时AFTER的触发器也不能修改NEW的过程变量(transitionvariables)。为了激活触发器,我执行了向表中的行插入s1=0的数据,之后只要执行符合LEFT(s2,1)<>'A'条件的动作都会失败: 财软,联盟,fs119.net
INSERTINTOt25VALUES(0,'a')/*primingthepump*///
INSERTINTOt25VALUES(5,'b')/*getserror'23000'*///
Don'tBelieveTheOldMySQLManual
该抛弃旧的MySQL的手册了
我在这里警告大家不要相信过去的MySQL手册中所说的了。我们已经去掉了关于触发器的错误的语句,但是仍旧有很多旧版本的手册在网上,举个例子,这是一个德国的Url上的: 财软联盟 fs119.net
这个手册上说触发器就是存储过程,忘掉吧,你也已经看见了,触发器就是触发器,而存储过程还是存储过程。 财软,联盟,fs119.net
手册上还说触发器可以从其他表上来删除,或者是当你删除一个事务的时候激发,无论他说的是什么意思,忘掉吧,MySQL不会去实现这些的。
财软联盟 fs119.net
最后关于说使用触发器会对查询速度产生影响的说法也是错的,触发器不会对查询产生任何影响。 财,软联盟,fs119.net
Bugs 财软,联盟,fs119.net
(不好的东西就不翻译了)
OnDecember142004,Ididan"AdvancedSearch"in
'triggers',Ifoundthattherewere17activebugsasofthatdate.Ofcoursetheymightdisappear
beforeyoureadthis,butjustincasetheyhaven't,I'llmentiontheimportantones.Ifthey'restill
there,you'llhavetoworkaroundthemwhenyou'retryingtriggers.
Bug#5859DROPTABLEdoesnotdroptriggers.
(删除表的时候没有自动删除触发器)
Whenyoudropatable,droppingthetable'striggersshouldbeautomatic. 财 管家园 fs119.net
Bug#5892Triggershavethewrongnamespace.
(触发器的命名空间有错,你必须在前面加上表的名字才能删除触发器,下面是例子)
Youhavetosay"DROPTRIGGER<tablename>.<triggername>".
Thecorrectwayis"DROPTRIGGER<triggername>". 财软.联盟.fs119.net
Bug#5894Triggerswithalteredtablescausecorruptdatabases.
(触发器对表的改变可能会造成数据库数据被破坏)
Donotalteratablethathasatriggeronit,untilyouknowthisisfixed. 财软联.盟.fs119.net
Conclusion最后
财管家园,fs119.net
到了书的最后,我认为不需要给大家复习或者是重温一下了,因为相信大家可以很轻松的记住上面所说的。 财软联盟.fs119.net
Google.cn搜索相关文章:
谷歌中搜索全球网 MySQL5.0新特性教程触发器:第一讲
百度中搜索 MySQL5.0新特性教程触发器:第一讲
谷歌中搜索www.fs119.net MySQL5.0新特性教程触发器:第一讲
下一篇:MySQL数据库SQL语法参考