Logik: Datenbank oder Anwendung / 2 (Constraints check)

8

Dies ist eine spezielle Version von diese Frage .
Ich möchte überprüfen, ob ich eine doppelte Zeile einfüge. Sollte ich es programmgesteuert in meiner Anwendungsebene überprüfen:

%Vor%

oder soll ich die Ausnahme abfangen, die von der Datenbankschicht ausgelöst wird und ausgelöst wird, wenn ich gegen den Verstoß verstoßen habe?

%Vor%

BEARBEITEN: Mit anderen Worten: Obwohl die Einschränkung bestehen bleibt (es ist sowieso ein gutes Datenbank-Design, und ich kann nicht sicher sein, dass meine App die einzige sein wird, die auf die Tabelle zugreift) Verlasse dich auf die Constraint und behandle die Exception, die durch die Verletzung verursacht wird. Oder sollte ich besser nachsehen?

EDIT2: Natürlich überprüfe ich + füge innerhalb einer Transaktion ein und sperre die Tabelle, um sicherzustellen, dass kein anderer Prozess in der Zwischenzeit einen anderen Datensatz schreibt

    
Manrico Corazzi 03.10.2008, 14:31
quelle

7 Antworten

7

Zuerst müssen Sie müssen einen Primärschlüssel oder eine eindeutige Einschränkung für die Datenbank haben, um diese Eindeutigkeit richtig durchzusetzen - keine Frage.

Wenn die Einschränkung existiert, welchen Code sollten Sie in der Anwendung codieren? Meine Vorliebe würde sein, die Einfügung zu versuchen und die Ausnahmen zu fangen. Da vermutlich die meisten Inserts erfolgreich sind, werden nur wenige als Duplikate fehlschlagen (das ist was "Ausnahme" bedeutet!): Es ist ineffizient, vor jedem Einfügen eine Existenzprüfung durchzuführen, wenn die Datenbank ohnehin ihre eigene Constraint-Prüfung durchführt.

Es ist theoretisch auch möglich, dass der exists-check sowieso falsch ist - wenn jemand anders einen Datensatz mit demselben Schlüsselwert in dem kleinen Intervall zwischen Ihrem exists-check und Ihrem insert eingibt. Wenn Sie dann die Datenbankausnahme nicht abfangen, werden Sie glauben, dass die Einfügung erfolgreich war, obwohl dies tatsächlich nicht der Fall war.

    
Tony Andrews 03.10.2008, 14:44
quelle
2

Sie überprüfen, ob das Objekt nur im Anwendungscode vorhanden ist, und speichern Sie das Objekt dann, sobald Sie sich vergewissert haben, dass dies nicht der Fall ist. Ein anderer gleichzeitiger Client fügt jedoch möglicherweise zwischen den beiden Codezeilen ein eigenes Objekt ein. Du würdest also sowieso eine Duplicate Exception bekommen, nur dieses Mal fängst du es nicht.

Sie müssen das Speichern () ausführen und die Ausnahme abfangen. Andernfalls haben Sie eine Race-Bedingung, wenn andere gleichzeitige Clients in derselben Datenbank arbeiten.

    
Bill Karwin 03.10.2008 16:13
quelle
2

Sie müssen die Datenbankausnahme abfangen, es sei denn, Sie können garantieren, dass Ihre Anwendung die einzige ist, die jemals Zeilen in Ihre Datenbank einfügt (und immer Zeilen einfügt).

BEARBEITEN: Ich mag die Frage falsch verstanden haben, aber ich würde immer noch argumentieren, dass Option B (HibernateSessionFactory löst die ConstraintException aus der Datenbank) die bessere Option ist. Es gibt immer eine kleine Chance, dass eine andere Anwendung etwas in die Zeit zwischen Ihrer Überprüfung und dem tatsächlichen Funktionsaufruf einfügen kann. Außerdem ist die einzige Möglichkeit, nach einem Betrogenen zu suchen, eine zusätzliche Abfrage durchzuführen, die nur eine unnötige Leistungsminderung darstellt.

Mein ursprüngliches Verständnis der Frage war, dass in Option A die Dublettenprüfung intern durchgeführt würde (d. h. indem nur die Datenstrukturen verwendet wurden, die das Programm bereits erstellt hatte, und ohne Abfrage bis zum INSERT). Meine ursprüngliche Antwort war eine Antwort auf diese Methode.

    
JPLemme 03.10.2008 14:37
quelle
1

Im Allgemeinen versuche ich, eine Codierung zu vermeiden, die darauf angewiesen ist, dass Fehler ausgelöst werden, weil ich etwas falsch gemacht habe. Manchmal ist das alles, was Sie tun können. In Ihrer Situation, ich denke, Sie sollten zuerst überprüfen.

    
wcm 03.10.2008 14:36
quelle
1

Dies wird unterbrochen (doppelte Einträge erlauben), wenn die Einschränkung aus irgendeinem Grund fallen gelassen wird (normalerweise Wartungsarbeiten, bei denen der DBA es versäumt, sie wieder zu aktivieren). Sie sollten diese Situation innerhalb der Anwendung überprüfen.

Es ist jedoch ein guter Datenbankentwurf, dass die Datenbank die Einschränkung erzwingt (wie Sie richtig angemerkt haben), da andere möglicherweise auch die Datenbank verwenden. Als eine Verallgemeinerung ist es am besten anzunehmen, dass Anwendungen und Datenbanken in einer M: M-Beziehung leben - dies wird fast immer der Fall sein.

    
quelle
1

Die Ausnahmen, die von Hibernate (oder einer beliebigen ORM-Komponente) ausgelöst werden, sind in der Regel schwer zu interpretieren.

Wenn die Ausnahme genügend Informationen enthält, dass Sie eine Fehlermeldung erzeugen können, die dem Benutzer tatsächlich hilft, fangen Sie einfach die Ausnahme ab, analysieren Sie sie und fahren Sie fort.

Wenn die Ausnahme nicht genügend Informationen enthält, müssen Sie nach der Fehlerbedingung suchen und eine hilfreiche Fehlermeldung an den Benutzer ausgeben, dass sie etwas falsch machen.

Die Frage ist: "Wie undurchsichtig ist die Ausnahme?" Einige sind ziemlich undurchsichtig. Andere haben genug, dass Sie die Nachrichtenzeichenfolge analysieren und herausfinden können, was Sie dem Benutzer sagen sollen.

    
S.Lott 03.10.2008 15:09
quelle
0

Sobald der Ruhezustand eine Ausnahme von der Sitzung auslöst, muss die Sitzung verwerfen (siehe Abschnitt 11.2.3). Also, wenn Sie auf Duplikate prüfen und die gleiche Sitzung fortsetzen müssen, haben Sie keine andere Wahl, als zuerst in der Anwendung zu überprüfen.

Es gibt auch eine Möglichkeit mit dem Code im ersten Snippet, dass ein anderer Prozess einen Datensatz einfügen könnte, der dazu führen würde, dass die doppelte Ausnahme zwischen dem Zeitpunkt der Dublettenüberprüfung und dem Zeitpunkt des Einfügens ausgelöst wird.

    
JMM 03.10.2008 15:11
quelle