2008-12-27 8 views
10

Ich habe kürzlich in Erlang getaucht, und ich entschied mich, Mnesia zu verwenden, um meine Datenbank-Arbeit zu tun, da es jede Art von Erlang-Datenstruktur problemlos speichern kann, mit Skala skalieren, mit Liste verwendet werden kann Comprehensions usw.Wahrung der relationalen Integrität mit Mnesia

Die meisten Zeilen, die aus SQL-Standarddatenbanken stammen, können und sollten durch einen Primärschlüssel identifiziert werden, normalerweise eine automatisch inkrementierende Ganzzahl. Standardmäßig betrachtet Mnesia das erste Feld einer Zeile als seinen Schlüssel. Es gibt auch keine Möglichkeit, einen inkrementierenden Ganzzahlschlüssel zu haben, soweit ich weiß.

Da ich diese fiktiven Aufzeichnungen meine Tabellen darstellen:

-record(user, {name, salt, pass_hash, email}). 
-record(entry, {title, body, slug}). 
-record(user_entry, {user_name, entry_title}). 

Ich stelle dar, den Benutzernamen verwenden für einige Zwecke gut genug sein kann, wie es mit dem Eintrag Titel, um die Ressource zu identifizieren, aber wie Ich gehe Integrität bewahren?

Angenommen, der Benutzer ändert seinen Namen oder der Titel des Eintrags ändert sich nach einer Bearbeitung. Wie stelle ich sicher, dass meine Daten immer noch korrekt verknüpft sind? Jede Tabelle mit dem Benutzernamen zu aktualisieren, wenn sie sich ändert, klingt wie eine schreckliche Idee, egal wie sie gestellt wird.

Was wäre der beste Weg, um irgendeine Art von Primärschlüssel-System in Mnesia zu implementieren?

Auch, wie würde eine intermediäre Tabelle wie 'user_entry' tun, wenn das erste Feld in der Regel der Schlüssel ist? Was wäre sonst eine bessere Möglichkeit, eine Viele-zu-Viele-Beziehung in Mnesien darzustellen?

Antwort

9

Ich bevorzuge die Verwendung von GUIDs anstelle von automatischen Inkrementierung von Ints als künstliche Fremdschlüssel. Es gibt eine Erlang uuid module verfügbar unter GitHub, oder Sie können {now(), node()} verwenden, vorausgesetzt, dass doc sagt: "Es ist auch garantiert, dass nachfolgende Aufrufe an diese BIF kontinuierlich steigende Werte zurückgibt."

Verwenden von etwas, das als der Primärschlüssel ändern kann, scheint mir eine schlechte Idee unabhängig vom Datenbanksystem zu sein.

Vergessen Sie nicht, dass Sie Daten in Mnesia nicht normalisieren müssen, selbst bis zur ersten Normalform;

-record(user, {id, name, salt, pass_hash, email, entries}). 
-record(entry, {id, title, body, slug, users}). 

wo entries und users sind Listen von ids: in Ihrem Beispiel, würde ich die folgende Struktur betrachten. Dies hängt natürlich von den gewünschten Suchanfragen ab.

BEARBEITEN: behoben, um viele-zu-viele anstatt viele-zu-eins zu sein.

+0

Ist es wirklich der gute Weg? es scheint, dass make_ref/0 seine Anzahl nach dem Neustart der Shell zurücksetzt und mehrere ähnliche Werte haben wird. Bedeutet das nicht, dass Sie nach einem Serverneustart schlechte Schlüssel bekommen könnten? Es könnte vielleicht helfen, es mit/0 zu koppeln. –

+1

Es ist wahrscheinlich besser, jetzt/0 mit Knoten/0 zu kombinieren. –

+0

Oder für die Angelegenheit, können Sie einfach das Uuid-Modul verwenden: http://github.com/travis/erlang-uuid/tree/master –

8

Mnesia unterstützt Sequenzen (autoinkrementierende Ganzzahlen) in Form von mnesia:dirty_update_counter(Table, Key, Increment). Um es zu verwenden, benötigen Sie eine Tabelle mit zwei Attributen Schlüssel und Anzahl. Trotz des Namens ist dirty_update_counter atomar, obwohl er nicht in einer Transaktion ausgeführt wird.

Ulf Wiger arbeitete in seiner rdbms package an der Bereitstellung von typischen RDBMS-Funktionen auf der Oberseite von Mnesia. Sein Code liefert Fremdschlüssel-Constraints, parametrische Indizes, Feldwert-Constraints und so weiter. Leider wurde dieser Code in zwei Jahren nicht aktualisiert und wird wahrscheinlich ohne viel Erlang Erfahrung schwierig zu laufen sein.

Beim Entwerfen und Verwenden von Mnesien sollten Sie daran denken, dass Mnesien keine relationale Datenbank ist. Es ist ein transaktionaler Schlüssel/Wert-Speicher und ist viel einfacher zu verwenden, wenn Sie nicht normalisieren.

Wenn Ihr Benutzername einzigartig ist, können Sie das Schema verwenden:

-record(user, {name, salt, pass_hash, email}). 
-record(entry, {posted, title, body, slug, user_name}). 

Wo posted der erlang ist: now() Zeit, wenn der Artikel hochgeladen. user_name benötigt möglicherweise einen sekundären Index, wenn Sie häufig eine Liste aller Artikel für einen Benutzer abrufen müssen. Da diese Daten auf zwei Tabellen aufgeteilt sind, müssen Sie Integritätsbedingungen in Ihrem Anwendungscode erzwingen (z. B. keine Einträge ohne gültigen Benutzernamen akzeptieren).

Jeder Feldwert in Mnesia kann ein beliebiger Erlang-Ausdruck sein. Wenn Sie also keinen eindeutigen Schlüssel für ein bestimmtes Feld haben, können Sie einige Felder kombinieren, um einen Wert zu erhalten, der immer eindeutig ist. vielleicht {Benutzername, DatePosted, TimePosted}. Mit Mnesia können Sie Teilschlüssel über mnesia:select(Table, MatchSpec) suchen. MatchSpecs sind ziemlich schwierig von Hand zu schreiben, also denken Sie daran, dass ets:fun2ms/1 eine Pseudo-Erlang-Funktion in eine Matchspec für Sie konvertieren kann.

In diesem Beispiel generiert fun2ms uns eine MatchSpec zum Durchsuchen einer Blogeintragstabelle -record(entry, {key, title, slug, body}). wo der Schlüssel {Username, {Year, Month, Day}, {Hour, Minute, Second}} ist - der Benutzername des Autors und das Datum und die Uhrzeit der Veröffentlichung des Artikels. Das folgende Beispiel ruft die Titel aller Blog-Beiträge von TargetUsername während Dezember 2008

ets:fun2ms(fun (#entry{key={U, {Y,M,_D}, _Time}, title=T}) 
      when U=:=TargetUsername, Y=:=2008, M=:=12 -> 
       T 
      end). 
+0

Ich denke "wo" sollte stattdessen "wann" sein. Danke auch für die tollen Erklärungen. –

Verwandte Themen