2013-04-11 12 views
11

z jakiegoś powodu, na maszynie MySQL 5.5.30, wyzwalacz, który usuwa wiersz z drugim stole nie ma już ognia usuwania spust na drugim stole.MySQL 05.05.30 kaskadowo wyzwalacze nie działa

Działa to doskonale na naszej lokalnej wersji MySQL 5.5.25

Nie mogę znaleźć żadnej dokumentacji, która by wyjaśnić ten problem, ma ktoś może mieć równe problem?

Jest to albo błąd, który występuje w wersji MySQL większa niż 5.5.25 lub „cecha”, która jest włączona przypadkowo.

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) 

OK tutaj powielać moich kroków:

Database

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

Stoły

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; 

wyzwalacze

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 ; 

Q: Dlaczego zacytować identyfikatorów używając cudzysłowia? (Zamiast backticks)

Bo mi się nie podoba "niszowych składni"

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) 

Test-obudowy 1: Oczekiwane zachowanie (wersja bazy danych 5.2.20)

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

mysql> SET GLOBAL general_log := ON; 

badania wkładka wyzwalania

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" 

oczekiwane zawartość tabeli:

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) 

badania zmiana wyzwalania, zestaw aktywny

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" 

oczekiwane zawartość tabeli:

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) 

testowanie aktualizacji spust, zestaw nieaktywna

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" 

oczekiwane zawartość tabeli:

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) 

Testcase2: nieoczekiwane zachowanie (MySQL w wersji 5.5.30)

Święty wyzwala grml - Wiesz co? Szkoda, że ​​nie testowałem drugi przypadek pierwszy - niestety nie udało mi się odtworzyć ten błąd .. test pracował na 5.5.30, a także będzie na bieżąco informować :)

EDIT wyzwalania nie kaskadowo z powodu nieznanego definiującego, który pozostał w zrzucie sql wykonanym dla produkcji. Usunięcie DEFINER = w zrzutach wyzwalaczy (alternatywnym rozwiązaniem byłoby utworzenie użytkownika lub zmiana DEFINER = na istniejący) rozwiązał problem, rozwiązał część problemu.

Nieznany definiujący nie powoduje żadnych wyjściowe pliku dziennika

+4

* pokaż rzeczywisty fragment kodu *, proszę. – Sebas

+0

Coś interesującego w dziennikach? Czy możesz stworzyć mały przykład na zupełnie nowej bazie danych, aby zilustrować problem? (Jeśli jest odtwarzalny, łatwiej go zrozumieć, imo). – halfer

+0

Hej, Michel, tak, jak powiedział Halfer, możesz podać przykład wzoru twojego stołu. – medina

Odpowiedz

8

końcowy wniosek: MySQL 5.05.30 nie ma błędy w tym przypadku również nie było błędną samego serwera.

Kilka self-made błędy spowodowane problem:

Mistake I: użytkownik DEFINER nie istniała

Zamiast po prostu generowanie bazy danych na maszynie produkcyjnej, byłem leniwy i dumpingowych bazę testów do maszyny produkcyjnej. Jeśli nie ustawisz wyraźnie wartości DEFINER w instrukcji CREATE TRIGGER, zostanie ona ustawiona na CURRENT_USER. Niestety ta dokładna CURRENT_USER na mojej maszynie wytrzymałościowej nie istnieje na serwerze produkcyjnym.

Mistake II: lenistwo

mysqldump zrzuca z definicji wyzwalacza Definer i tworzenie spust powinien generować ostrzeżenie, ale znowu, byłem leniwy i zrobił coś takiego ..

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

Ten wygląda cool (omg maniakiem) i oszczędza dużo pliku zrzutu pchania, ale surpresses ostrzeżenia można zobaczyć podczas ładowania zrzutu z poziomu konsoli

MySQL pisze po około wykrywaniem spustowych:

przypadku określenia klauzuli definiujący zasady te ustalenia prawne wartości użytkownika Definer:

Jeśli nie masz uprawnień SUPER, jedyną legalną wartością użytkownika jest własne konto, określone dosłownie lub przy użyciu CURRENT_USER. Nie można ustawić definicji na inne konto.

Jeśli masz uprawnienie SUPER, możesz podać dowolną nazwę konta składniowego o nazwie składniowej . Jeśli konto w rzeczywistości nie istnieje, generowane jest ostrzeżenie .

Choć możliwe jest, aby utworzyć wyzwalacz z nieistniejącej DEFINER uwagę, że nie jest to dobry pomysł na takie wyzwalacze być aktywowane aż konto faktycznie istnieje. W przeciwnym razie zachowanie w odniesieniu do sprawdzania uprawnień jest niezdefiniowane.

Źródło: http://dev.mysql.com/doc/refman/5.5/en/create-trigger.html

Mistake III: lenistwo

mam bardzo fajne opakowanie mysqldump, który jest w stanie wygenerować czyste, wielokrotnego użytku pliki zrzutu. Podczas nadpisywania wyzwalaczy bez DEFINERA miałem otwartą transakcję konsoli (blokowanie table2) na serwerze produkcyjnym, więc wyzwalacze na table2 nie aktualizowały się wcale, ale z powodu mojego potoku danych sql na 5 serwerach nie widziałem limitu czasu błąd.

Wniosek:

Nie było błędów, tylko wyzwalacze nie zostały utworzone poprawnie ..

Czasami powinieneś przestać być leniwy, dając ważnych rzeczy do nieco więcej czasu i uwagi możesz zaoszczędzić dużo czasu !!

1

Wyzwalacze w MySQL (w przeciwieństwie do procedur przechowywanych) są zawsze uruchamiane w kontekście DEFINER. Wyzwalacze mogą wydawać się niedziałające, ponieważ DEFINER nie ma uprawnień do wykonania niektórych lub wszystkich wyzwalaczy. W szczególności w MySQL 5.1 i nowszych DEFINER musi mieć uprawnienie TRIGGER, jak również odpowiednie uprawnienia i/lub .

Jeśli wyzwalacze nie działają, sprawdź uprawnienia.