Domänenobjekte als IDs verursachen einige komplexe / subtile Probleme:
Serialisierung / Deserialisierung
Wenn Sie Objekte als Schlüssel speichern, wird die Serialisierung des Objektdiagramms äußerst kompliziert. Sie erhalten stackoverflow
Fehler , wenn aufgrund der Rekursion eine naive Serialisierung JSON oder XML zu tun. Sie müssen dann einen benutzerdefinierten Serializer schreiben, der die tatsächlichen Objekte konvertiert, um ihre IDs zu verwenden, anstatt die Objektinstanz zu serialisieren und die Rekursion zu erstellen.
Übergeben Sie Objekte zur Typensicherheit, speichern Sie jedoch nur IDs. Anschließend können Sie eine Zugriffsmethode verwenden, die die zugehörige Entität beim Aufruf verzögert lädt. Das Caching der zweiten Ebene kümmert sich um nachfolgende Anrufe.
Subtile Referenzlecks:
Wenn Sie Domänenobjekte in Konstruktoren verwenden, wie Sie sie dort haben, erstellen Sie Zirkelverweise, bei denen es sehr schwierig ist, Speicher für Objekte zurückzugewinnen, die nicht aktiv verwendet werden.
Ideale Situation:
Undurchsichtige IDs vs int / long:
Ein id
sollte ein vollständig undurchsichtiger Bezeichner sein, der keine Informationen darüber enthält, was er identifiziert. Es sollte jedoch eine gewisse Bestätigung bieten, dass es sich um eine gültige Kennung in seinem System handelt.
Rohe Typen brechen dies:
int
, long
Und String
sind die am häufigsten rohen Typen für Bezeichner in RDBMS - System verwendet. Es gibt eine lange Geschichte praktischer Gründe, die Jahrzehnte zurückreichen, und alle sind Kompromisse, die entweder zum Sparen space
oder zum Sparen time
oder zu beidem passen .
Sequentielle IDs sind die schlimmsten Straftäter:
Wenn Sie eine sequentielle ID verwenden, packen Sie standardmäßig zeitliche semantische Informationen in die ID. Welches ist nicht schlecht, bis es verwendet wird. Wenn Leute anfangen, Geschäftslogik zu schreiben, die die semantische Qualität der ID sortiert oder filtert, dann schaffen sie eine Welt voller Schmerzen für zukünftige Betreuer.
String
Felder sind problematisch, weil naive Designer Informationen in den Inhalt packen, normalerweise auch zeitliche Semantik.
Diese machen es unmöglich, auch ein verteiltes Datensystem zu erstellen, da 12437379123
es global nicht eindeutig ist. Die Wahrscheinlichkeit, dass ein anderer Knoten in einem verteilten System einen Datensatz mit derselben Nummer erstellt, ist so gut wie garantiert, wenn Sie genügend Daten in einem System erhalten.
Dann beginnen Hacks, es zu umgehen, und das Ganze verwandelt sich in einen Haufen dampfenden Chaos.
Wenn Sie große verteilte Systeme ( Cluster ) ignorieren , wird dies zu einem Albtraum, wenn Sie versuchen, die Daten auch mit anderen Systemen zu teilen. Besonders wenn das andere System nicht unter Ihrer Kontrolle ist.
Sie haben genau das gleiche Problem, wie Sie Ihre ID global eindeutig machen können.
UUID wurde aus einem Grund erstellt und standardisiert:
UUID
kann unter allen oben aufgeführten Problemen leiden, je nachdem, welche Version
Sie verwenden.
Version 1
Verwendet eine MAC-Adresse und Zeit, um eine eindeutige ID zu erstellen. Dies ist schlecht, da es semantische Informationen über Ort und Zeit enthält. Das ist an sich kein Problem, wenn naive Entwickler sich für die Geschäftslogik auf diese Informationen verlassen. Dadurch werden auch Informationen verloren, die bei Eindringversuchen ausgenutzt werden könnten.
Version 2
Die Verwendung eines Benutzers UID
oder eines GID
Domians UID
oder GUI
anstelle der Zeit Version 1
davon ist genauso schlimm wie Version 1
für Datenlecks und das Risiko, dass diese Informationen in der Geschäftslogik verwendet werden.
Version 3
ist ähnlich, ersetzt jedoch die MAC-Adresse und die Zeit durch einen MD5
Hash eines Arrays byte[]
von etwas, das definitiv eine semantische Bedeutung hat. Es gibt keinen Datenverlust, über den Sie byte[]
sich Sorgen machen müssen. Der Datenverlust kann nicht behoben werden UUID
. Dies gibt Ihnen eine gute Möglichkeit, UUID
Instanzformulare und externe Schlüssel deterministisch zu erstellen .
Version 4
basiert nur auf Zufallszahlen, was eine gute Lösung ist, es enthält absolut keine semantischen Informationen, aber es ist nicht deterministisch wiederherstellbar.
Version 5
ist genauso wie Version 4
aber verwendet sha1
statt md5
.
Domänenschlüssel und Transaktionsdatenschlüssel
Ich bevorzuge Domänenobjekt-IDs, wenn ich sie aus technischen Gründen verwende Version 5
oder Version 3
wenn ich sie nicht verwenden darf Version 5
.
Version 3
eignet sich hervorragend für Transaktionsdaten, die möglicherweise auf viele Computer verteilt sind.
Verwenden Sie eine UUID, es sei denn, Sie sind durch Speicherplatz eingeschränkt:
Sie sind garantiert eindeutig, geben Daten aus einer Datenbank aus und laden sie erneut in eine andere. Sie mussten sich nie um doppelte IDs sorgen, die tatsächlich auf unterschiedliche Domänendaten verweisen.
Version 3,4,5
sind völlig undurchsichtig und so sollten sie sein.
Sie können eine einzelne Spalte als Primärschlüssel mit einem UUID
und dann zusammengesetzte eindeutige Indizes für einen natürlichen zusammengesetzten Primärschlüssel haben.
Speicher muss auch nicht sein CHAR(36)
. Sie können das UUID
Feld in einem nativen Byte- / Bit- / Zahlenfeld für eine bestimmte Datenbank speichern, solange es noch indizierbar ist.
Erbe
Wenn Sie unformatierte Typen haben und diese nicht ändern können, können Sie sie dennoch in Ihrem Code abstrahieren.
Wenn Sie einen Version 3/5
von UUID
Ihnen verwenden, können Sie das Class.getName()
+ String.valueOf(int)
als a übergeben byte[]
und einen undurchsichtigen Referenzschlüssel haben, der neu erstellt und deterministisch ist.