检测更新查询是否来自触发器

时间:2017-03-21 10:58:28

标签: mysql triggers

我有一个名为pledgeRating的表,用于存储用户评分。在每个插入中,我运行以下触发器来更新ratingsCount表中的ratingpledgeTemplate列:

CREATE DEFINER=`trigger`@`%` TRIGGER `project87`.`pledgeRating_AFTER_INSERT` AFTER INSERT ON `pledgeRating` FOR EACH ROW
BEGIN
    UPDATE `pledgeTemplate` 
        SET `rating` = ((`rating` * `ratingsCount`) + NEW.rating) / (`ratingsCount` + 1),
            `ratingsCount` = `ratingsCount` + 1
        WHERE `id` = NEW.pledgeTemplateID;
END

为了完整起见,我想阻止所有mysql用户直接更新ratingsCount表中的ratingpledgeTemplate列。我希望仅从触发器更新这两列。

为了实现这一点,我在pledgeTemplate表中创建了一个新的触发器来验证运行更新查询的用户,但我找不到一种方法来检测该更新是否来自触发器:

CREATE DEFINER=`trigger`@`%` TRIGGER `project87`.`pledgeTemplate_BEFORE_UPDATE` BEFORE UPDATE ON `pledgeTemplate` FOR EACH ROW
BEGIN
    IF (OLD.ratingsCount != NEW.ratingsCount OR OLD.rating != NEW.rating) AND {{Update query is not from the trigger}} THEN
        SIGNAL sqlstate '45000' SET message_text = 'Error: Only trigger can modify ratingsCount or rating columns';
    END IF;
END

是否可以从第一个触发器传递一个标志,以便我可以在第二个触发器中检测到查询是否来自触发器?我查看了CURRENT_USER对象和USER()函数,因为我认为这些可能会有所帮助。但是CURRENT_USER总是设置为DEFINERUSER()始终返回运行初始查询的用户。

那么,有没有办法检测pledgeTemplate表上的更新查询是否从触发器或“直接”更新中运行?

1 个答案:

答案 0 :(得分:0)

您好_

首先我开始在评论中解释我的想法,但似乎它变得太长而且格式不正确。所以这只是一个想法,我不知道你是否对它好,但我会分享它:

  1. ALTER TABLE pledgeTemplate ADD COLUMN isTriggerUpdate BIT NULL DEFAULT 0; - 所以我们在表格中添加一个列,我们可以将其用作标志来确定更新是来自触发器还是来自用户
  2. 2

    CREATE DEFINER=`trigger`@`%` TRIGGER `project87`.`pledgeRating_AFTER_INSERT` 
    AFTER INSERT ON `pledgeRating` FOR EACH ROW
    BEGIN
        UPDATE `pledgeTemplate` 
            SET `rating` = ((`rating` * `ratingsCount`) + NEW.rating) / (`ratingsCount` + 1),
                `ratingsCount` = `ratingsCount` + 1,
                `isTriggerUpdate ` = 1
            WHERE `id` = NEW.pledgeTemplateID;
    END
    

    更改触发器的代码 pledgeRating_AFTER_INSERT ,将标志列设置为true

    3

    CREATE DEFINER=`trigger`@`%` TRIGGER `project87`.`pledgeTemplate_BEFORE_UPDATE` 
    BEFORE UPDATE ON `pledgeTemplate` FOR EACH ROW
    BEGIN
        IF (OLD.ratingsCount != NEW.ratingsCount OR OLD.rating != NEW.rating) 
           AND NEW.isTriggerUpdate != 1 THEN
            SIGNAL sqlstate '45000' SET message_text = 'Error: Only trigger can modify ratingsCount or rating columns';
        END IF;
    END
    

    现在你可以像这样在 pledgeTemplate_BEFORE_UPDATE 中找到缺失的条件。

    我认为这将作为逻辑工作,但问题是,这是实现这一目标的最有效逻辑。在此逻辑中,您无需在任何情况下将 isTriggerUpdate 列公开到前端,因为只需将其设置为true即可绕过此逻辑......

    祝你好运!