2008-10-03 8 views
8

Dies ist eine spezifische Version von this question.
Ich möchte überprüfen, ob ich eine doppelte Zeile einfügen. Soll ich es überprüfen programmatisch in meiner Anwendungsschicht:Logik: Datenbank oder Anwendung/2 (Constraints check)

if (exists(obj)) 
{ 
    throw new DuplicateObjectException(); 
} 
HibernateSessionFactory.getSession().save(obj); 

oder sollte ich die Ausnahme von der Datenbank-Ebene geworfen zu fangen und dann ausgelöst, wenn ich die contraint verletzen?

try 
{ 
    HibernateSessionFactory.getSession().save(obj); 
} 
catch(ConstraintViolationException e) 
{ 
    throw new DuplicateObjectException(); 
} 

EDIT: Mit anderen Worten: wenn die Einschränkung gibt es zu bleiben (es ist gut, Datenbank-Design wie auch immer, und ich kann meine app wird die einzige Zugriff auf die Tabelle nicht sicher sein) soll ich vertrauen auf die Bedingung und behandeln die Ausnahme ihre Verletzung erhöht, oder ich sollte besser überprüfen?

EDIT2: Natürlich I + prüfe einfügen innerhalb einer Transaktion, Sperren der Tabelle kein anderer Prozess, um sicherzustellen, einen weiteren Rekord in der Zwischenzeit

Antwort

7

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

Vorausgesetzt, dass die Einschränkung existiert, welchen Weg 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 Einfügungen 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 Abhängigkeitsprüfung durchführt.

Es ist theoretisch auch möglich, dass die exists-Prüfung sowieso falsch ist - wenn es jemand anderes schafft, einen Datensatz mit demselben Schlüsselwert in dem kleinen Intervall zwischen Ihrer exists-Prüfung und Ihrer Einfügung festzuschreiben. Wenn Sie die Datenbankausnahme nicht abfangen, glauben Sie, dass die Einfügung erfolgreich war, obwohl dies tatsächlich nicht der Fall war.

1

Im Allgemeinen schreiben, versuche ich Codierung zu vermeiden, die auf Fehler beruht geworfen werden, weil ich etwas falsch gemacht habe. Manchmal ist das alles, was Sie tun können. In Ihrer Situation sollten Sie zuerst nachsehen.

2

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

EDIT: Ich mag die Frage falsch verstanden haben, aber ich würde immer noch argumentieren, dass Option B (HibernateSessionFactory wirft die ConstraintException aus der Datenbank) ist die bessere Option. 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 Dupe-Prüfung intern durchgeführt würde (d. H. Indem nur die Datenstrukturen verwendet wurden, die das Programm bereits erstellt hatte, und ohne Abfrage bis INSERT). Meine ursprüngliche Antwort war eine Antwort auf diese Methode.

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 nicht wieder aktiviert). Sie sollten diese Situation innerhalb der Anwendung überprüfen.

Es ist jedoch ein gutes Datenbankdesign, 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.

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 dem Benutzer eine hilfreiche Fehlermeldung anzeigen, dass sie etwas falsch machen.

Die Frage ist eine von "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.

0

Sobald Hibernate eine Ausnahme von der Sitzung wirft Sie must discard the session (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, an dem Sie nach dem doppelten Datensatz suchen, und dem Zeitpunkt, an dem er eingefügt wird, ausgelöst wird.

2

Sie überprüfen, ob das Objekt nur in Anwendungscode vorhanden ist, und wenn das Ergebnis nicht zufriedenstellend ist, speichern Sie das Objekt munter. Ein anderer gleichzeitiger Client fügt jedoch möglicherweise zwischen den beiden Codezeilen ein eigenes Objekt ein. Sie würden also sowieso eine Duplicate-Ausnahme erhalten, nur diesmal nicht.

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