是否可以暂时禁用扳机,但仅用于一张桌子。

例如,我的表格,带有On Insert,更新和删除触发器的tablea。我也有一个具有相同触发器的表B,但它们仅影响表A中的某些列。

我现在有一个使用两个表的更新查询。我知道表中的更新需要发射触发器,但是表B中的更新绝对不需要发射触发器。因此,我想禁用这些触发器,直到完成更新为止。

这可能吗?我正在使用mysql 5.1

附录

这本质上是一个触发桌子

BEGIN
    IF (OLD.status != 1 AND NEW.status = 2) THEN
        IF (OLD.geo_lat IS NOT NULL AND OLD.geo_long IS NOT NULL) THEN
            DELETE FROM geo WHERE datatype IN (3,4) AND foreignid = NEW.id;
        END IF;
    ELSEIF (OLD.Status = 1 AND NEW.Status != 2) THEN
        IF (NEW.geo_lat IS NOT NULL AND NEW.geo_long IS NOT NULL) THEN
            INSERT INTO geo (datatype, foreignid, long, lat, hostid, morton, status) VALUES  (IF(NEW.groupType=1,3,4), NEW.id, NEW.geo_long, NEW.geo_lat, NEW.hostid, 0, NEW.Status);
        END IF;
    ELSEIF (NEW.status != 3) THEN  
        IF (OLD.geo_lat IS NOT NULL AND OLD.geo_long IS NOT NULL AND (NEW.geo_lat IS NULL OR NEW.geo_long IS NULL)) THEN
            DELETE FROM geo WHERE datatype IN (3,4) AND foreignid = NEW.id;
        ElSEIF ((OLD.geo_lat IS NULL OR OLD.geo_long IS NULL) AND NEW.geo_lat IS NOT NULL AND NEW.geo_long IS NOT NULL) THEN
            INSERT INTO geo (datatype, foreignid, longitude, latitude, hostid, morton, status) VALUES  (IF(NEW.groupType=1,3,4), NEW.id, NEW.geo_long, NEW.geo_lat, NEW.hostid, 0, NEW.Status);
        ELSEIF (OLD.geo_lat!=NEW.geo_lat OR OLD.geo_long != NEW.geo_long OR OLD.status != NEW.status) THEN
            UPDATE geo SET lat = NEW.geo_lat, long = NEW.geo_long, status = NEW.status WHERE datatype IN (3,4) AND foreignid = NEW.id;
        END IF;
    END IF;
END

这是表B上的触发器本质上

CREATE TRIGGER `usergroups_comments_insert` AFTER INSERT ON `usergroups_comment`
    FOR EACH ROW
    BEGIN
       CALL sp-set-comment_count(NEW.`gid`);
    END;

这是从表B发射的存储过程

DELIMITER $$

CREATE PROCEDURE `sp_set-comment_count` (IN _id INT)
BEGIN
   -- AC   - All Count
   -- OLDAC- Old All Count
   DECLARE AC, OLDAC INT DEFAULT 0;

   SELECT COUNT(*) AS ac
     INTO AC
     FROM usergroups AS ug
LEFT JOIN usergroup_comments AS ugm ON ugm.`gid` = ug.`id`
LEFT JOIN mediagallery AS dm ON ugm.mid = dm.`id`
    WHERE dm.`status` NOT IN (200, 201, 202, 203, 204, 205)
      AND ug.`id` = _id;

   SELECT allCount
     INTO OLDAC
     FROM usergroups
    WHERE ug.`id` = _id;

IF (OLDAC <> AC) THEN 

   UPDATE usergroups
      SET allCount = AC,
    WHERE usergroups.`id` = _id;

END IF;

END $$
有帮助吗?

解决方案

实际上,如果将IF放置在每个触发器中,则可以有效地关闭所有触发器。这是这样的代码块

IF @TRIGGER_DISABLED = 0 THEN
    ...trigger body
END IF;

在MySQL环境中,您可以

  • SET @TRIGGER_DISABLED = 1;
  • 进行数据维护
  • SET @TRIGGER_DISABLED = 0;

因此,您的表A触发器应该看起来像这样:

BEGIN 
    IF @TRIGGER_DISABLED = 0 THEN
    IF (OLD.status != 1 AND NEW.status = 2) THEN 
        IF (OLD.geo_lat IS NOT NULL AND OLD.geo_long IS NOT NULL) THEN 
            DELETE FROM geo WHERE datatype IN (3,4) AND foreignid = NEW.id; 
        END IF; 
    ELSEIF (OLD.Status = 1 AND NEW.Status != 2) THEN 
        IF (NEW.geo_lat IS NOT NULL AND NEW.geo_long IS NOT NULL) THEN 
            INSERT INTO geo (datatype, foreignid, long, lat, hostid, morton, status) VALUES  (IF(NEW.groupType=1,3,4), NEW.id, NEW.geo_long, NEW.geo_lat, NEW.hostid, 0, NEW.Status); 
        END IF; 
    ELSEIF (NEW.status != 3) THEN   
        IF (OLD.geo_lat IS NOT NULL AND OLD.geo_long IS NOT NULL AND (NEW.geo_lat IS NULL OR NEW.geo_long IS NULL)) THEN 
            DELETE FROM geo WHERE datatype IN (3,4) AND foreignid = NEW.id; 
        ElSEIF ((OLD.geo_lat IS NULL OR OLD.geo_long IS NULL) AND NEW.geo_lat IS NOT NULL AND NEW.geo_long IS NOT NULL) THEN 
            INSERT INTO geo (datatype, foreignid, longitude, latitude, hostid, morton, status) VALUES  (IF(NEW.groupType=1,3,4), NEW.id, NEW.geo_long, NEW.geo_lat, NEW.hostid, 0, NEW.Status); 
        ELSEIF (OLD.geo_lat!=NEW.geo_lat OR OLD.geo_long != NEW.geo_long OR OLD.status != NEW.status) THEN 
            UPDATE geo SET lat = NEW.geo_lat, long = NEW.geo_long, status = NEW.status WHERE datatype IN (3,4) AND foreignid = NEW.id; 
        END IF; 
    END IF; 
    END IF; 
END 

因此,您的表B触发器应该看起来像这样:

CREATE TRIGGER `usergroups_comments_insert` AFTER INSERT ON `usergroups_comment`     
    FOR EACH ROW     
    BEGIN     
        IF @TRIGGER_DISABLED = 0 THEN
            CALL sp-set-comment_count(NEW.`gid`);     
        END IF;
    END;     

如果要启动表A的触发器,但不适合表B,请仅将代码块添加到表B的触发器中。

其他提示

您可以简化这种方法。

  1. 只需在第一个“开始”块中添加标签。
  2. 测试,如果控制变量不是null。
  3. 如果是,请留下扳机。

因此,您可以避免将原始触发代码包装到“ If”统计中。仅必须以明确的方式修改扳机头 - 这更简单,更可靠。

例子:

CREATE TRIGGER [YOUR_TRIGGER_SPEC]
Trigger: BEGIN

      IF @TRIGGER_DISABLED NOT NULL THEN
         LEAVE Trigger;
      END IF;

      [YOUR CODE]
END;

玩得开心 :-)

Rolandomysqldba编辑2012-05-01 18:38 EDT

实际上,我几个月前尝试了,这是不稳定的。这是:

示例表

mysql> show create table mytext\G
*************************** 1. row ***************************
       Table: mytext
Create Table: CREATE TABLE `mytext` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `txt` text NOT NULL,
  `txtmd5` char(32) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `txtmd5` (`txtmd5`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> select * from mytext;
+----+------------------------+----------------------------------+
| id | txt                    | txtmd5                           |
+----+------------------------+----------------------------------+
|  1 | Rolando Edwards        | ab14209a029a8f6d42d7c5a5d7a77623 |
|  2 | Pamela Edwards         | 5dcbd06ea48c690032b1b29a514eb0e2 |
|  3 | Dominique Edwards      | 7487431d74ac2d17a9d63123672a4bdf |
|  4 | Diamond Edwards        | bc8d80541a000ed506048134058e2878 |
|  5 | The Quick Brown Fox    | be94284cfa534c1837e744c061f71e17 |
| 11 | Quick Brown Fox Jumped | 495a52136057b242a80e514d7cbe77c7 |
+----+------------------------+----------------------------------+
6 rows in set (0.00 sec)

mysql>

这是触发器:

DROP TRIGGER IF EXISTS mytext_bi;
DELIMITER $$
CREATE TRIGGER mytext_bi BEFORE INSERT ON mytext FOR EACH ROW
TheTrigger:BEGIN
    DECLARE found_count INT;
    SELECT COUNT(1) INTO found_count
    FROM mytext WHERE txtmd5 = MD5(LEFT(new.txt,10));
    IF found_count = 1 THEN
        LEAVE TheTrigger;
    END IF;
    SET new.txtmd5 = MD5(LEFT(new.txt,10));
END $$
DELIMITER ;

看看我试图插入“ Dominique Edwards”的情况会发生什么

mysql> insert into mytext (txt) values ('Dominique Edwards');
Query OK, 1 row affected (0.06 sec)

mysql> select * from mytext;
+----+------------------------+----------------------------------+
| id | txt                    | txtmd5                           |
+----+------------------------+----------------------------------+
|  1 | Rolando Edwards        | ab14209a029a8f6d42d7c5a5d7a77623 |
|  2 | Pamela Edwards         | 5dcbd06ea48c690032b1b29a514eb0e2 |
|  3 | Dominique Edwards      | 7487431d74ac2d17a9d63123672a4bdf |
|  4 | Diamond Edwards        | bc8d80541a000ed506048134058e2878 |
|  5 | The Quick Brown Fox    | be94284cfa534c1837e744c061f71e17 |
| 11 | Quick Brown Fox Jumped | 495a52136057b242a80e514d7cbe77c7 |
| 14 | Dominique Edwards      |                                  |
+----+------------------------+----------------------------------+
7 rows in set (0.00 sec)

mysql>

啊,无论如何它都滑入了!!!

我仍然会+1您的答案,不仅是因为您的努力,还因为我尝试了完全相同的事情(将标签放在附近 BEGIN)那对我不起作用。多么的学习方式。

没有人应该完全相信MySQL存储的程序语言(信号处理未正确实施),并且您强调说,当您说“玩得开心”时。 有时,玩得开心意味着尝试一下!!!. 。那就是学习的真正精神。

我这样围绕着它:

DROP TRIGGER IF EXISTS mytext_bi;
DELIMITER $$
CREATE TRIGGER mytext_bi BEFORE INSERT ON mytext FOR EACH ROW
BEGIN
    DECLARE found_count INT;
    SELECT COUNT(1) INTO found_count
    FROM mytext WHERE txtmd5 = MD5(LEFT(new.txt,10));
    IF found_count = 0 THEN
        SELECT COUNT(1) INTO found_count FROM table_that_does_not_exist;
    END IF;
    SET new.txtmd5 = MD5(LEFT(new.txt,10));
END $$
DELIMITER ;

存储过程的性质是要么像我在答案中所做的那样经过完整的代码,或者使用信号处理(同样,它不是完全操作)

欢迎来到DBA Stackexchange !!!同样,+1按承诺。

很抱歉长期编辑,但我无法将我的示例代码放在评论中。

首先:感谢您的“ +1” :-)

而且 - 您是对的:触发器的禁用并不能自行阻止动作。目前,MySQL实现了这种“流产”的信号。

正如您在答案中所描述的那样,常见的“解决方法”是为了提出SQL的外观。因此,将通过副作用(例外)来防止整个动作。

但是:要小心。这种“解决方案”有时会产生更多的问题 - 考虑交易触发器和重新Quired - 希望受到控制的回滚。 uuuups! (那是为什么我使用这种方法的配额标记)。

此外,调试此类实施是一个非常困难的事情。有了这种行为,开发人员,管理员或维护者必须能够在“良好” SQL远程上区分和真正发生的问题。可怕。

最后并非最不重要的一点是:这种限制命中了MySQL中的每个存储例程(过程,功能和触发器)!

实际上:缺乏控制是RDBMS的每个提供商的责任。和Yepp-这就是我的意思是“玩得开心” :-)

对,回到根源 - 问题是:“禁用触发器”(不能防止动作)。特别是对于这种特殊要求,该方法是安全可靠的。

另一个信息“在szene”背后:提供的方法可以安全,因为MySQL初始化了基于sessionb的变量,例如null的'@trigger_disabled' - 这也是副作用。

请记住:这种变量仅在当前会话中可见!因此,您可以禁用当前会话的触发器。这种实现没有“服务器范围”的效果!

如果您需要此类内容(整个服务器禁用触发器),则必须使用服务器范围可见且可供电的对象,例如服务器变量(uuups-另一种具有不可预测的副作用的“解决方法”)或 - 更清洁的方式 - 桌子。

因此,我的长期回答也很“抱歉”:

许可以下: CC-BY-SA归因
不隶属于 dba.stackexchange
scroll top