gpt4 book ai didi

MySQL 5.5.30 级联触发器不起作用

转载 作者:IT王子 更新时间:2023-10-28 23:43:56 25 4
gpt4 key购买 nike

出于某种原因,在 MySQL 5.5.30 机器上,从第二个表中删除行的触发器不再触发第二个表上的删除触发器。

这在我们本地的 MySQL 版本 5.5.25 上完美运行

我没有找到任何可以解释这种行为的文档,有人可能有同样的问题吗?

这要么是 MySQL 5.5.25 以上版本中出现的错误,要么是意外启用的“功能”。

UPDATE table1 => fires BEFORE UPDATE trigger ON table1
table1 BEFORE UPDATE TRIGGER executes: DELETE FROM table2 => should fire BEFORE DELETE trigger on table2 ( but doesn't )
table 2 BEFORE DELETE TRIGGER executes: DELETE FROM table3 (never happens)

这里是我重现的步骤:

数据库

CREATE DATABASE "triggerTest" DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

表格

CREATE TABLE "table1" (
"id" int(11) NOT NULL AUTO_INCREMENT,
"active" tinyint(1) NOT NULL DEFAULT '0',
"sampleData" varchar(100) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
PRIMARY KEY ("id")
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=DYNAMIC;


CREATE TABLE "table2" (
"id" int(11) NOT NULL AUTO_INCREMENT,
"table1_id" int(11) NOT NULL DEFAULT '0',
PRIMARY KEY ("id"),
CONSTRAINT "test2_fk_table1_id" FOREIGN KEY ("table1_id") REFERENCES "table1" ("id") ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=DYNAMIC;


CREATE TABLE "table3" (
"id" int(11) NOT NULL AUTO_INCREMENT,
"table1_id" int(11) NOT NULL DEFAULT '0',
PRIMARY KEY ("id"),
CONSTRAINT "test3_fk_table1_id" FOREIGN KEY ("table1_id") REFERENCES "table1" ("id") ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=DYNAMIC;

触发器

DELIMITER $$

CREATE TRIGGER "table1_rtrg_AI" AFTER INSERT ON "table1" FOR EACH ROW
BEGIN
IF NEW."active" THEN
INSERT INTO "table2" ( "table1_id" ) SELECT NEW."id";
END IF;
END$$

CREATE TRIGGER "table1_rtrg_BU" BEFORE UPDATE ON "table1" FOR EACH ROW
BEGIN
IF NOT NEW."active" AND OLD."active" THEN
DELETE FROM "table2" WHERE "table1_id" = OLD."id";
END IF;

IF NEW."active" AND NOT OLD."active" THEN
INSERT INTO "table2" ( "table1_id" ) SELECT NEW."id";
END IF;
END$$

CREATE TRIGGER "table2_rtrg_AI" AFTER INSERT ON "table2" FOR EACH ROW
BEGIN
INSERT INTO "table3" ( "table1_id" ) SELECT NEW."table1_id";
END$$

CREATE TRIGGER "table2_rtrg_BD" BEFORE DELETE ON "table2" FOR EACH ROW
BEGIN
DELETE FROM "table3" WHERE "table1_id" = OLD."table1_id";
END$$

DELIMITER ;

问:为什么使用双引号引用标识符? (而不是反引号)

因为我不喜欢“小众语法”

    mysql> show variables LIKE 'sql_mode';
+---------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value |
+---------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
| sql_mode | PIPES_AS_CONCAT,**ANSI_QUOTES**,IGNORE_SPACE,NO_UNSIGNED_SUBTRACTION,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+---------------+------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

测试用例 1:预期行为(数据库版本 5.2.20)

mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.5.20 |
+-----------+
1 row in set (0.00 sec)

mysql> SET GLOBAL general_log := ON;

测试插入触发器

mysql> INSERT INTO "table1" ( "active", "sampleData" ) SELECT 0, 'sample data row 1';
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0

general_log:
130423 12:51:27 78010 Query INSERT INTO "table1" ( "active", "sampleData" ) SELECT 0, 'sample data row 1'


mysql> INSERT INTO "table1" ( "active", "sampleData" ) SELECT 1, 'sample data row 2';
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0

general_log:
130423 12:51:33 78010 Query INSERT INTO "table1" ( "active", "sampleData" ) SELECT 1, 'sample data row 2'
78010 Query INSERT INTO "table2" ( "table1_id" ) SELECT NEW."id"
78010 Query INSERT INTO "table3" ( "table1_id" ) SELECT NEW."table1_id"

预期的表格内容:

mysql> SELECT * FROM "table1";
+----+--------+-------------------+
| id | active | sampleData |
+----+--------+-------------------+
| 1 | 0 | sample data row 1 |
| 2 | 1 | sample data row 2 |
+----+--------+-------------------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM "table2";
+----+-----------+
| id | table1_id |
+----+-----------+
| 1 | 2 |
+----+-----------+
1 row in set (0.00 sec)

mysql> SELECT * FROM "table3";
+----+-----------+
| id | table1_id |
+----+-----------+
| 1 | 2 |
+----+-----------+
1 row in set (0.00 sec)

测试更新触发器,设置激活

mysql> UPDATE "table1" SET "active" = 1 WHERE "id" = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

query_log:
130423 12:52:15 78010 Query UPDATE "table1" SET "active" = 1 WHERE "id" = 1
78010 Query INSERT INTO "table2" ( "table1_id" ) SELECT NEW."id"
78010 Query INSERT INTO "table3" ( "table1_id" ) SELECT NEW."table1_id"

预期的表格内容:

mysql> SELECT * FROM "table1";
+----+--------+-------------------+
| id | active | sampleData |
+----+--------+-------------------+
| 1 | 1 | sample data row 1 |
| 2 | 1 | sample data row 2 |
+----+--------+-------------------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM "table2";
+----+-----------+
| id | table1_id |
+----+-----------+
| 2 | 1 |
| 1 | 2 |
+----+-----------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM "table3";
+----+-----------+
| id | table1_id |
+----+-----------+
| 2 | 1 |
| 1 | 2 |
+----+-----------+
2 rows in set (0.00 sec)

测试更新触发器,设置为非事件

mysql> UPDATE "table1" SET "active" = 0 WHERE "id" = 2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0

query_log:

130423 12:52:49 78010 Query UPDATE "table1" SET "active" = 0 WHERE "id" = 2
78010 Query DELETE FROM "table2" WHERE "table1_id" = NEW."id"
78010 Query DELETE FROM "table3" WHERE "table1_id" = OLD."table1_id"

预期的表格内容:

mysql> SELECT * FROM "table1";
+----+--------+-------------------+
| id | active | sampleData |
+----+--------+-------------------+
| 1 | 1 | sample data row 1 |
| 2 | 0 | sample data row 2 |
+----+--------+-------------------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM "table2";
+----+-----------+
| id | table1_id |
+----+-----------+
| 2 | 1 |
+----+-----------+
1 row in set (0.00 sec)

mysql> SELECT * FROM "table3";
+----+-----------+
| id | table1_id |
+----+-----------+
| 2 | 1 |
+----+-----------+
1 row in set (0.00 sec)

测试用例 2:意外行为(MySQL 版本 5.5.30)

Holy triggers grml - 你知道吗?遗憾的是我没有首先测试第二种情况 - 不幸的是我无法重现错误.. 测试也适用于 5.5.30,会让你更新:)

编辑触发器没有级联,因为未知定义器保留在为生产制作的 sql 转储中。删除触发器转储中的 DEFINER=(替代解决方案是创建用户或将 DEFINER= 更改为现有用户)解决了问题,解决了部分问题。

未知的定义者没有导致任何日志文件输出

最佳答案

最终结论:MySQL 5.5.30 在这种情况下没有问题,服务器本身也没有配置错误。

几个自己犯的错误导致了这个问题:

错误一:DEFINER 用户不存在

我不只是在生产机器上生成数据库,而是偷懒并将测试数据库转储到生产机器上。如果您没有在 CREATE TRIGGER 语句中显式设置 DEFINER,则将其设置为 CURRENT_USER。不幸的是,我的测试机器上的这个确切的 CURRENT_USER 在生产服务器上不存在。

错误二:懒惰

mysqldump使用 DEFINER 转储触发器定义并创建触发器应该生成警告,但我又懒惰并做了类似的事情..

mysqldump --triggers --routines -h test -p database | gzip -3 | ssh production "gunzip -c | mysql -h production_database_host -p production_database"

看起来很酷(omg geek)并为您节省大量转储文件推送,但它抑制了您在从控制台中加载转储时可能会看到的警告

MySQL 写了以下关于触发器定义器的内容:

If you specify the DEFINER clause, these rules determine the legal DEFINER user values:

If you do not have the SUPER privilege, the only legal user value is your own account, either specified literally or by using CURRENT_USER. You cannot set the definer to some other account.

If you have the SUPER privilege, you can specify any syntactically legal account name. If the account does not actually exist, a warning is generated.

Although it is possible to create a trigger with a nonexistent DEFINER account, it is not a good idea for such triggers to be activated until the account actually does exist. Otherwise, the behavior with respect to privilege checking is undefined.

Source: http://dev.mysql.com/doc/refman/5.5/en/create-trigger.html

错误三:懒惰

我有一个非常酷的 mysqldump 包装器,它能够生成干净、可重用的转储文件。在没有 DEFINER 的情况下覆盖触发器时,我在生产服务器上打开了一个控制台事务(锁定 table2),因此 table2 上的触发器根本没有更新,而是再次更新,因为我的数据 sql 管道超过 5 个服务器,我没有看到超时错误。

结论:

没有错误,只是没有正确创建触发器..

有时你应该停止偷懒,给重要的事情多一点时间和关注可以为你节省很多时间!!

关于MySQL 5.5.30 级联触发器不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15950702/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com