Mysql 5.7 & 8.0 -24章-存储程序和视图 (翻译+理解)

24.3 使用触发器

触发器是与表关联的数据库对象,并在表发生特定事件时激活。触发器的一些用途是执行对要插入表中的值的检查,或者对更新中涉及的值进行计算。

触发器定义为在语句插入,更新或删除关联表中行的时候被激活。这些行操作是触发事件。例如,可以通过 INSERT或LOAD DATA语句插入行,并为每个插入的行激活插入触发器。可以将触发器设置为在触发事件之前或之后激活。例如,您可以在插入表中的每一行之前或更新的每一行之后激活触发器。

重要
MySQL触发器仅在使用SQL语句对表进行更改的时候才会激活。这包括对可更新视图的基础表的更改。对于不将SQL语句传输到MySQL服务器的API所做的更改,触发器不会激活。这意味着使用NDB的API 进行的更新不会激活触发器。
更改INFORMATION_SCHEMAperformance_schema表不会激活触发器 。这些表实际上是视图上不允许的视图和触发器。

以下部分描述了创建和删除触发器的语法,显示了如何使用它们的一些示例,并指出了如何获取触发器元数据。

其他资源

24.3.1 触发器语法和示例

要创建触发器或删除触发器,请使用 第13.1.22节“创建触发器语法”第13.1.34节“DROP TRIGGER语法”中所述的 CREATE TRIGGERDROP TRIGGER语句。
下面是一个简单的示例,它将触发器与表关联起来,以激活INSERT操作。触发器充当累加器,将插入到表的一列中的值相加。
在这里插入图片描述

CREATE TRIGGER语句创建一个与account表关联的名为ins_sum的触发器。它还包括指定触发器操作时间,触发事件以及触发器激活时要执行的操作的子句:

  • 关键字BEFORE表示触发操作时间。在这种情况下,触发器在每行插入表格之前激活。这里允许的另一个关键字是AFTER
  • 关键字INSERT表示触发事件; 也就是说,激活触发器的操作类型。在该示例中,INSERT 操作导致触发器激活。您还可以创建触发器DELETEUPDATE操作。
  • 以下语句FOR EACH ROW 定义了触发器主体; 也就是说,每次触发器激活时执行的语句,对于受触发事件影响的每一行都会发生一次。在该示例中,触发器主体是一个简单的 SET ,它将插入到amount列中的值累积到用户变量中。该语句引用列 NEW.amount,表示 “ 要插入新行的amount列的值 ” 。

要使用触发器,请将@sum变量设置为零,执行INSERT语句,然后查看变量后面的值:
在这里插入图片描述
在这种情况下,语句执行INSERT后@sum的值是 14.98 + 1937.50 - 100,即 1852.48。

要销毁触发器,请使用DROP TRIGGER语句。如果触发器不在默认数据库中,则必须指定数据库名称:
--
如果删除表,则表的任何触发器也将被删除。

触发器名称存在于数据库命名空间中,这意味着所有触发器必须在数据库中具有唯一名称。不同数据库中的触发器可以具有相同的名称。

可以为具有相同触发事件和操作时间的给定表定义多个触发器。例如,您可以BEFORE UPDATE为表创建两个触发器。默认情况下,具有相同触发事件和操作时间的触发器按创建顺序激活。要影响触发器顺序,请在FOR EACH ROW指示之后指定子句,FOLLOWS或者 指定PRECEDES具有相同触发事件和操作时间的现有触发器的名称。使用时 FOLLOWS,新触发器在现有触发器之后激活;使用时PRECEDES,新触发器在现有触发器之前激活。

例如,以下为account表定义了另一个BEFORE INSERT 触发器 :
--

触发器ins_transaction类似于 ins_sum但分别累积存款和取款。它有一个PRECEDES 部分,使它在 ins_sum 之前激活; 没有该子句,它会在ins_sum之后激活,因为它是在ins_sum之后创建的 。

在触发器主体中,使用OLD和 NEW关键字可以访问受触发器影响的行中的列。OLD和NEW是MySQL触发器的扩展; 它们不区分大小写。

在INSERT触发器中,只能使用NEW.col_name; 没有old行。在DELETE触发器中,只能使用OLD.col_name; 没有new行。在 UPDATE触发器中,您可以使用OLD.col_name 引用在更新之前的列,NEW.col_name更新后引用该行的列。

名为OLD列是只读的。您可以参考它(如果您有SELECT 权限),但不能修改它。NEW如果您具有该 SELECT权限,则可以引用名为的列。在 BEFORE触发器中,如果您拥有UPDATE权限,也可以通过SET NEW.col_name = value更改其值。这意味着您可以使用触发器来修改要插入新行或用于更新行的值。(这样的 SET语句对AFTER触发器没有影响,因为行已经发生了变化。)

在一个BEFORE触发器中,NEW 对于一个AUTO_INCREMENT列的值时0,实际上没有被插入新行时自动生成的序列号。

通过使用该BEGIN … END构造,您可以定义执行多个语句的触发器。在BEGIN块中,您还可以使用存储例程(例如条件和循环)中允许的其他语法。但是,就像存储例程一样,如果使用mysql命令行定义了执行多个语句的触发器,则必须重新定义mysql语句分隔符delimiter ,以便可以;在触发器定义中使用语句分隔符。以下示例说明了这些要点。它定义了一个UPDATE 触发器,用于检查要用于更新每一行的新值,并将值修改为0到100之间的范围。这必须是BEFORE触发器,因为在用于更新行之前必须检查该值:
--

可以更容易地单独定义存储过程,然后从触发器中使用简单的CALL语句调用它 。如果要从多个触发器中执行相同的代码,这也是有利的。

触发器在激活时执行的语句中可能出现的内容有一些限制:

  • 触发器不能使用该CALL 语句来调用将数据返回给客户端或使用动态SQL的存储过程。(允许存储过程通过OUT或INOUT 参数将数据返回到触发器 。)

  • 触发不能使用语句或明或暗地开始或结束一个事务,如 START TRANSACTION,COMMITROLLBACK。(ROLLBACK to SAVEPOINT被允许,因为它不会结束一个事务。)。

另请参见 第C.1节“存储程序的限制”

MySQL在触发器执行期间处理错误,如下所示:

  • 如果BEFORE触发器失败,则不执行相应行上的操作。

  • BEFORE触发由 尝试插入或修改行的操作 激活 ,而不管尝试是否成功。

  • 一个AFTER触发器 只有当任何执BEFORE触发器和行操作成功执行后才会执行。

  • 在BEFORE或 AFTER触发器期间的错误导致导致触发器调用的整个语句失败。

  • 对于事务表,语句失败应导致回滚语句执行的所有更改。触发器失败会导致语句失败,因此触发器失败也会导致回滚。对于非事务性表,无法执行此类回滚,因此尽管语句失败,但在错误点之前执行的任何更改仍然有效。

触发器可以按名称包含对表的直接引用,例如此示例中的testref触发器:
--
假设您将以下值插入表中 test1,如下所示:
在这里插入图片描述
结果,4张表中的数据分别是 :
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lengfengyuyu/article/details/84066845