南大通用GBase8s 常用SQL语句(104)

级联触发器

数据库服务器允许除 Select 触发器外的其它触发器级联,也就是说,一个触发器的触发器操作可以激活另一个触发器。(有关级联 Select 触发器的限制的更多信息,请参阅 Select 触发器被激活时的情况。)

级联序列中触发器的最大数目是 61:即初始触发器加上最多 60 个级联触发器。当序列中的级联触发器数目超过最大值时,数据库服务器返回错误号码 -748,带有一些信息:

Exceeded limit on maximum number of cascaded triggers.

下一个示例说明在 stores_demo 数据库中的 manufact 、stock 和 items 表上实施引用完整性的级联触发器序列。当从 manufact 表删除制造商是,第一个触发器 del_manu 从 stock 表中删除该制造商的所有条目。stock 表中的每个 DELETE 激活第二个触发器 del_items,该触发器从 items 表删除该制造商的所有 items。最终,items 表中的每个 DELETE 触发 SPL 例程 log_order,同时在不能再被填充的 orders 表中创建所有订单的记录。

CREATE TRIGGER del_manu

        DELETE ON manufact REFERENCING OLD AS pre_del

        FOR EACH ROW(DELETE FROM stock WHERE manu_code = pre_del.manu_code);

        CREATE TRIGGER del_stock

        DELETE ON stock REFERENCING OLD AS pre_del

        FOR EACH ROW(DELETE FROM items WHERE manu_code = pre_del.manu_code);

        CREATE TRIGGER del_items

        DELETE ON items REFERENCING OLD AS pre_del

        FOR EACH ROW(EXECUTE PROCEDURE log_order(pre_del.order_num));

当您不使用日志记录时,manufact 和 stock 表上的引用完整性约束都阻止该示例中的触发器执行。但是,当您使用日志记录时,触发器成功执行,因为约束检查被延迟,直至所有的触发操作(包括级联触发器的操作)都完成。关于执行触发器时如何处理约束的信息,请参阅约束检查。

除了不修改触发 UPDATE 语句别更新的任何列的 UPDATE 语句或 INSERT 语句外,数据库服务器通过不允许您修改任何级联触发器操作中的触发表俩防止触发器循环。INSERT 触发器可以在同一个表上定义 UPDATE 触发操作。

约束检查

当您使用日志记录时,数据库服务器延迟触发语句上的约束检查,直至触发操作列表中的语句执行之后。这等同于执行触发语句前执行 SET CONSTRAINTS ALL DEFERRED 语句。完成触发操作后,数据库服务器有效执行 SET CONSTRAINTS constraint IMMEDIATE 语句以检查延迟的约束。该操作允许您写入触发器以便是触发器操作能够解析触发语句创建的任何违例。有关更多信息,请参阅 SET Database Object Mode 语句。

考虑以下示例,表 child 具有约束 r1,该约束引用表 parent。您定义触发器 trig1 并使用 INSERT 语句激活它。在触发操作中,trig1 检查 parent 是否具有 child 中当前 cola 具有的值的行;如果没有,将插入该行。

CREATE TABLE parent (cola INT PRIMARY KEY);

     CREATE TABLE child (cola INT REFERENCES parent CONSTRAINT r1);

        CREATE TRIGGER trig1 INSERT ON child

        REFERENCING NEW AS new

        FOR EACH ROW

        WHEN((SELECT COUNT (*) FROM parent

        WHERE cola = new.cola) = 0)

        -- parent row does not exist

        (INSERT INTO parent VALUES (new.cola));

当您将一行插入到引用约束中的子表中时,该行可能在父表中不存在。数据库服务器不立即在触发语句上返回此错误。相反,它允许触发操作通过将相应的行插入父表来解析约束违例。如先前示例所示,您可以在触发操作内检查父行是否存在,如果存在,则可以提供逻辑以绕过 INSERT 操作。

对于没有日志记录的数据库,数据库服务器不延迟触发语句上的约束检查。在此情况中,如果触发语句违反约束,则数据库服务器立即返回错误。

您不能在触发操作中使用 SET Transaction Mode 语句。当您激活触发器时,数据库服务器检查此约束,因为该语句可能在 UDR 中发生。

防止触发器相互覆盖

当您使用 UPDATE 语句激活多个触发器时,触发器可能覆盖较早触发器所做的更改。如果您不希望触发操作相互作用,则可以将该 UPDATE 语句分为多个 UPDATE 语句,每个语句更新单个列。

另一个办法是,您可以为需要触发操作的所有列创建单个更新触发器。然后,在触发操作内,您可以测试正被更新的列并以希望的顺序应用操作。但是,这种方法与让数据库服务器应用单个触发器的操作不同,并且有以下缺点:

  • 如果触发 UPDATE 语句将列设置为当前值,则您无法检测 UPDATE ,因此触发操作被跳过。您可能希望执行触发操作,即使列值尚未被更改。
  • 如果触发器具有 BEFORE 操作,则它应用于所有列,因为您尚无法检测某列是否被更改。

远程数据库中的表

您无法在驻留于当前数据库之外的表或视图上创建触发器。但是,您可以在本地表上定义触发器,该表的触发操作操纵了本地服务器实例的另一个数据库中的表,或另一个服务器实例的数据库中的表。

以下示例在本地 GBase 8s 服务器实例 dbserver1 (它的会话是已连接的)的当前数据库中的 newtab 表上定义了 Update 触发器。此处触发操作在远程 dbserver2 GBase 8s 服务器实例的数据库中的 items 表上指定了 UPDATE 操作:

CREATE TRIGGER upd_nt UPDATE ON newtab

        REFERENCING NEW AS post

        FOR EACH ROW(UPDATE stores_demo@dbserver2:items

        SET quantity = post.qty WHERE stock_num = post.stock

        AND manu_code = post.mc);

总之,存在于本地数据库中的触发器支持本地、跨数据库和跨服务器的触发操作:

  1. 在本地数据库中表上的本地触发操作
  2. 在本地服务器实例的另一个数据库的表上跨数据库触发操作
  3. 在远程服务器实例的数据库的表上的跨服务器触发操作。

定义在远程服务器实例的数据库上的触发器的跨服务器触发操作可以是激活本地数据库中的一个或多个触发器的事件,本地触发器的触发操作不能是跨服务器操作。如果来自远程数据库服务器的 SELECT 、DELETE 、INSERT 、MERGE 或 UPDATE 语句是激活本地触发器(其操作指定了远程数据库实例的数据库的表)的事件,则触发操作失败。

例如,以下触发操作的组合和触发语句在触发语句执行时产生错误:

-- Trigger action from dbserver1 to dbserver3:

        CREATE TRIGGER upd_nt UPDATE ON newtab

        REFERENCING NEW AS post

        FOR EACH ROW(UPDATE stores_demo@dbserver3:items

        SET quantity = post.qty WHERE stock_num = post.stock

        AND manu_code = post.mc);

        

        -- Triggering statement from dbserver2:

        UPDATE stores_demo@dbserver1:newtab

        SET qty = qty * 2 WHERE s_num = 5

        AND mc = 'ANZ';

以上的 UPDATE 语句在运行时不会返回错误,因为跨服务器的触发事件不会触发另一个跨服务器操作。

重要: 作为安全预防措施,用户仅保留角色的自由访问权,不能通过视图或触发器通过对单独去数据库外表的访问。跨数据库触发操作和跨除雾器触发操作需要非本地数据库和直接授权给用户或者授权到 PUBLIC 组的表的存取权限。

日志记录和恢复

您可以为数据库创建触发器,使其带有或不带有日志记录。如果具有事务日志记录的数据库中的触发器失败,则触发语句和触发操作会回滚,就好像这些操作时触发语句的扩展那样,但是其它事务不回滚。

但是,在不具有事务日志记录的数据库中,当触发语句失败时,您不能回滚。在此情况中,您负责维护数据库中的数据完整性。触发语句的 UPDATE 、INSERT 或 DELETE 操作在 FOR EACH ROW 部分中的触发操作前发生。如果没有日志记录的数据库中的触发操作失败,则应用程序必须将触发语句更改的行恢复到先前值。

如果触发操作调用 UDR,但是 UDR 在异常处理部分终止,则该部分中修改数据的任何操作都随触发语句回滚。在以下部分示例中,当异常处理程序陷入错误时,它在表 logtab 中插入一行:

ON EXCEPTION IN (-201)

        INSERT INTO logtab values (errno, errstr);

        RAISE EXCEPTION -201

        END EXCEPTION;

但是,当 RAISE EXCEPTION 语句返回错误时,数据库服务器回滚该 INSERT ,因为它是触发操作的一部分。如果 UDR 在触发操作外执行,则 INSERT不回滚。

实现触发操作的 UDR 不能包含任何 BEGIN WORK 、COMMIT WORK 或 ROLLBACK WORK 语句。如果数据库具有事务日志记录,则您必须在触发语句前开始显式事务,或者该语句本身必须是显式事务。无论哪种情况,UDR 中任何其它与事务相关的语句都无效。

您可以使用触发器实施数据库服务器当前不支持的引用操作。在没有日志记录的数据库中,当触发语句失败时,您负责维护数据完整性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值