MySQL Inputvalidierung mit Triggern

Ich finds sehr praktisch, direkt auf Datenbankseite soviel wie möglich zu erledigen. Da wirds dann auch noch einen Artikel zu geben. Ich wurde neulich von Oracle inspiriert, wo folgende Konstrukte möglich sind:

create table Product
( 
	ProdNr integer constraint PK_Product primary key,
	ProdPreis integer constraint min_price check (ProdPreis >= 10)
);

Damit rejected Oracle Werte kleiner als 10 für ProdPreis beim Insert / Update – super Sache und besser als das in der Application-Logik ausschließen zu müssen. Einzig doof daran ist, dass man solche Fehler sinnvoll im Programm abfangen muss und mit sprechenden Fehlermeldungen quittieren muss – sonst kanns für unbedarfte Programmierer verwirrend werden, warum denn gewisse Werte nicht in der Datenbank eingefügt werden können.

Check ist cool – aber nicht für MySQL

Zwar ist check auch in MySQL implementiert, tut aber einfach mal nichts. Als Workaround kann man für sowas Trigger verwenden, die vor Updates / Inserts automatisch aufgerufen werden und damit den gleichen Zweck erfüllen.

Sowas kann dann zum Beispiel so aussehen:

DELIMITER //
	CREATE TRIGGER min_price_four_ins 
	BEFORE INSERT ON pizza 
	FOR EACH ROW 
	BEGIN 
		DECLARE foobar INT;
		IF NEW.price < 4 THEN 
			SELECT `Das ist die Fehlermeldung` INTO foobar FROM pizza;
		END IF; 
	END; //
DELIMITER ;

Erstmal kryptisch und verwirrend, schauen wir uns das mal step-by-step an:

  1. Der Trigger wird vor einem Insert auf die Tabelle pizza ausgeführt.
  2. FOR EACH ROW: Der Trigger wird für jede einzufügende Zeile ausgelöst
  3. Es wird eine int-Variable angelegt und eine Fehlermeldung als String in diese Variable eingelesen. Hier wirds verwirrend. Das Konstrukt ist deswegen nötig, weil der Trigger fehlschlagen muss, um das Insert zu verhindern. Nun gibt es in MySQL kein throw exception oder fail(), also muss anderweitig ein Fehler ausgelöst werden. In diesem Fall wird also ein String in eine int-Variable eingelesen.

Schauen wir uns die Funktion des Triggers mal an:

INSERT INTO pizza (pizzaname, price) VALUES ('Salami', 3.95);

Und – wie erwartet – wird keine Zeile eingefügt und die Fehlermeldung ausgegeben:

#1054 - Unknown column 'Das ist die Fehlermeldung' in 'field list'

Der Trigger muss nun nochmal für Update angelegt werden und schon ist die nicht vorhandene Check-Funktionalität emuliert.

Mit Triggern lässt sich natürlich noch viel mehr machen, etwa auch andere Tabellen abfragen, Werte updaten etc. Aber Vorsicht: Es sollte irgendwo an prominenter Stelle im Programmcode selbst notiert werden, welche Trigger existieren und was sie genau für eine Funktion haben. Sonst kann sowas zu großer Verwirrung führen ;).

Wer detaillierter einsteigen möchte, sei auf das MySQL-Manual zu CREATE TRIGGER verwiesen.

Weitere Posts:

Dieser Beitrag wurde unter Datenbanken, webdev veröffentlicht. Setze ein Lesezeichen auf den Permalink.

4 Antworten auf MySQL Inputvalidierung mit Triggern

  1. Pingback: Lasst die Datenbank ihren Job machen! | davblog: webdev and stuff

  2. Ralph Meier sagt:

    Noch vor nicht allzu langer Zeit dachte ich, dass es super einfach und cool ist, möglichst viel auf die Datenbank auszulagern ( Validierung, Berechnungen usw. ). Ich weiss, die verschiedenen Datenbanken bieten dies und es wird auch häufig benutzt.

    Aber ist das wirklich richtig? Verletzt es nicht das Single Responsibility Principle von SOLID? Was ist die eigentliche Aufgabe einer Datenbank? Ich denke es ist die Persistierung der Daten.

    Ich kann aus persönlicher Erfahrung in Projekten sagen, dass das Auslagern von Validierungen und Funktionalität in die Datenbank Probleme entstehen können:
    – Ein Datenbankwechsel wird praktisch verunmöglicht
    – Entwickler müssen noch eine 2. Sprache beherrschen ( z.B. Stored Procedures in der DB )
    – SRP wird verletzt
    – Validierungen und Funktionen auf der gleichen Abstraktionsebene werden auf verschiedene Applikationsschichten verteilt.

    Was meinst Du dazu?

    • david sagt:

      Servus Ralph, danke für deine Anmerkung.

      Gerade bei Triggern bin ich ziemlich zwiegespalten, wie im Artikel gen Ende dann hoffentlich auch rumkommt. Würde es eine funktionierende CHECK-Klausel unter MySQL geben, wäre die wohl mein bester Freund. Grad bei Triggern gehts dann aber schon los, dass man erstmal auf den Trichter kommen muss, dass es da noch „Trigger-Magie“ im Untergrund gibt. Und man kommt auch zudem noch leicht in die Trigger-Hölle, weil man den Durchblick verliert, wer jetzt eigentlich gerade wen wann auslöst.

      Aber selbst wenn man mit der CHECK-Klausel als MySQL Entwickler versorgt wäre, bleibt das Problem bestehen – Man muss als Programmierer genau wissen, wo man nachschauen muss, um Anpassungen vorzunehmen. Von daher gebe ich dir da schon recht. Ich denke man muss sowas immer im Einzelfall betrachten.

  3. Carsten W. sagt:

    Ich denke es ist die Persistierung der Daten.

    Und die Überwachung der Richtigkeit dieser Daten! Eine Datenbank ist kein dummer Datenspeicher.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.