2008-10-28 10 views
15

Ich habe eine bestimmte POJO, die in einer Datenbank persistent sein muss, aktuelle Design spezifiziert sein Feld als eine einzelne Zeichenfolge Spalte, und das Hinzufügen von zusätzlichen Feldern zu der Tabelle ist keine Option.Hausgemachte vs Java-Serialisierung

Bedeutung, die Objekte müssen in irgendeiner Weise serialisiert werden. Also nur für die grundlegende Implementierung ging ich und entwarf meine eigene serialisierte Form des Objekts, die alle Felder in eine nette Zeichenfolge verkettet, getrennt durch ein Trennzeichen, das ich wählte. Aber das ist ziemlich hässlich und kann Probleme verursachen, sagen wir, wenn eines der Felder mein Trennzeichen enthält.

Also habe ich grundlegende Java-Serialisierung versucht, aber von einem grundlegenden Test, den ich durchgeführt habe, wird dies irgendwie eine sehr kostspielige Operation (Aufbau eines ByteArrayOutputStream, eines ObjectOutputStream, usw. für die Deserialisierung).

Was sind meine Optionen? Was ist der bevorzugte Weg für die Serialisierung von Objekten in einer Datenbank?

Bearbeiten: Dies wird eine sehr häufige Operation in meinem Projekt sein, so muss der Aufwand auf ein Minimum gehalten werden, und die Leistung ist von entscheidender Bedeutung. Auch Lösungen von Drittanbietern sind nett, aber nicht relevant (und in der Regel Overhead erzeugen, die ich zu vermeiden versuche)

Antwort

12

Elliot Rusty Harold schrieb eine nice argument gegen die Verwendung der Java-Objekt-Serialisierung für die Objekte in seiner XOM-Bibliothek. Die gleichen Prinzipien gelten für Sie. Die integrierte Java-Serialisierung ist Java-spezifisch, fragil und langsam und sollte daher am besten vermieden werden.

Sie haben ungefähr die richtige Idee, ein String-basiertes Format zu verwenden. Das Problem besteht darin, dass Sie mit Trennzeichen auf Formatierungs-/Syntaxprobleme stoßen. Die Lösung besteht darin, ein Format zu verwenden, das bereits dafür gebaut wurde. Wenn dies ein standardisiertes Format ist, können Sie möglicherweise auch andere Bibliotheken/Sprachen verwenden, um es zu manipulieren. Ein string-basiertes Format bedeutet auch, dass Sie die Hoffnung haben, es zu verstehen, indem Sie einfach die Daten ansehen; Binärformate entfernen diese Option.

XML und JSON sind zwei großartige Optionen; Sie sind standardisiert, textbasiert, flexibel, lesbar und verfügen über umfangreiche Bibliotheksunterstützung. Sie werden auch überraschend gut funktionieren (manchmal sogar schneller als Java-Serialisierung).

+3

Ich habe festgestellt, XML und JSON sind etwa 5x langsamer als Java-Serialisierung. Hast du Beispiele, wo sie schneller sind? –

+1

Die integrierte Java-Serialisierung ist ebenfalls JVM-spezifisch.Nicht wirklich portierbar – mcjabberz

+0

Es gibt nichts in diesem Link, das ein "nettes Argument" oder gar ein Argument darstellt. Nur eine Reihe von überflüssigen Bemerkungen, nicht alle richtig. – EJP

3

Betrachten Sie die Daten in einem Properties Objekt setzen und verwenden seine load()/store() Serialisierung. Das ist eine textbasierte Technik, so dass es in der Datenbank noch lesbar ist:

public String getFieldsAsString() { 
    Properties data = new Properties(); 
    data.setProperty("foo", this.getFoo()); 
    data.setProperty("bar", this.getBar()); 
    ... 
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    data.store(out, ""); 
    return new String(out.toByteArray(), "8859-1"); //store() always uses this encoding 
} 

aus Zeichenfolge zu laden, kann ähnlich ein neues Objekt Properties und load() die Daten verwenden.

Dies ist besser als Java-Serialisierung, weil es sehr lesbar und kompakt ist.

Wenn Sie Unterstützung für verschiedene Datentypen benötigen (d. H. Nicht nur für String), verwenden Sie BeanUtils, um jedes Feld in und aus einer Zeichenfolgendarstellung zu konvertieren.

+0

Jason danke für deine Hilfe, die letzten beiden Lösungen sind leider irrelevant dafür. Können Sie das erste näher erläutern? –

+0

Sicher! Siehe meine aktualisierte Antwort. –

2

Ich würde sagen, Ihr erster Ansatz ist nicht so schlimm, wenn Ihr POJO aus Strings und primitiven Typen besteht. Sie können das Maskieren des Trennzeichens erzwingen, um Beschädigungen zu vermeiden. Wenn Sie Hibernate verwenden, kapseln Sie die Serialisierung in einem custom type.

Wenn Ihnen eine andere Abhängigkeit nichts ausmacht, ist Hessian angeblich eine effizientere Möglichkeit, Java-Objekte zu serialisieren.

3

XStream oder YAML oder OGNL kommen als einfache Serialisierungstechniken in den Sinn. XML war am häufigsten, aber OGNL bietet die größte Flexibilität mit der geringsten Menge an Metadaten.

1

Sie können die Serialisierung optimieren, indem Sie Ihr Objekt externalisieren. Das gibt Ihnen die vollständige Kontrolle darüber, wie es serialisiert wird und die Prozessleistung verbessert. Dies ist einfach zu tun, solange Ihr POJO einfach ist (d. H. Keine Verweise auf andere Objekte hat), andernfalls können Sie die Serialisierung leicht unterbrechen.

tutorial here

EDIT: Nicht impliziert dies die bevorzugte Methode ist, aber Sie sind in Ihrer Optionen sehr begrenzt, wenn ti Leistung entscheidend ist und Sie können nur einen String-Spalte in der Tabelle.

0

Ich habe einen bestimmten POJO, der in einer Datenbank gespeichert werden muss, das aktuelle Design gibt sein Feld als einzelne Stringspalte an und das Hinzufügen zusätzlicher Felder zur Tabelle ist keine Option.

Können Sie eine neue Tabelle erstellen und einen Fremdschlüssel in diese Spalte einfügen?!? :) Ich vermute nicht, aber lassen Sie uns alle Basen abdecken!

Serialisierung: Wir hatten diese Diskussion vor kurzem, so dass wir, wenn unsere Anwendung abstürzt, sie im gleichen Zustand wie zuvor wiederbeleben können. Wir versenden im Wesentlichen ein persistentes Ereignis in eine Warteschlange, und dann greift es das Objekt, sperrt es und serialisiert es dann. Das scheint ziemlich schnell zu sein. Wie viele Daten werden serialisiert? Können Sie Variablen vorübergehend machen (d. H. Zwischengespeicherte Variablen)? Können Sie Ihre Serialisierung aufteilen? Vorsicht: Was passiert, wenn sich Ihre Objekte ändern (sperren) oder Klassen wechseln (andere Serialisierungs-ID)? Sie müssen alles, was serialisiert ist, auf die neuesten Klassen aufrüsten. Vielleicht musst du das nur über Nacht speichern, es ist also egal.

XML: Sie könnten etwas wie xstream verwenden, um dies zu erreichen. Etwas Brauchbares zu bauen ist möglich (eine nette Interviewfrage!), Aber ich würde es wahrscheinlich nicht selbst machen. Warum die Mühe? Denken Sie daran, wenn Sie zyklische Links haben oder wenn Sie mehr als einmal auf Objekte verweisen. Der Wiederaufbau der Objekte ist nicht ganz so trivial.

Datenbankspeicher: Wenn Sie mit Oracle 10g Blobs zu speichern, ein Upgrade auf die neueste Version, da c/Blob-Performance massiv erhöht. Wenn wir große Mengen von Daten sprechen, zippen Sie vielleicht den Ausgabestrom?

Ist dies eine Echtzeit-App, oder gibt es eine zweite oder zwei Pausen, in denen Sie das tatsächliche Objekt sicher beibehalten können? Wenn Sie Zeit haben, können Sie es klonen und den Klon dann in einem anderen Thread beibehalten. Wofür ist die Beständigkeit? Ist es wichtig, dass es innerhalb einer Transaktion ausgeführt wird?

0

Überlegen Sie, Ihr Schema zu ändern. Selbst wenn Sie einen schnellen Weg finden, ein POJO zu einem String zu serialisieren, wie gehen Sie mit verschiedenen Versionen um? Wie migriert man die Datenbank von X-> Y? Oder schlimmer von A-> D? Ich sehe Probleme, bei denen wir ein serialisiertes Objekt in einem BLOB-Feld gespeichert haben und einen Kunden über mehrere Versionen hinweg migrieren müssen.

4

Sie müssen die Versionierung in Ihrer Lösung in Betracht ziehen.Dateninkompatibilität ist ein Problem, das bei jeder Lösung auftreten wird, bei der eine binäre Serialisierung des Objekts verwendet wird. Wie lädt man eine ältere Datenzeile in eine neuere Version des Objekts?

Also die Lösungen, die über die Serialisierung zu einem Name/Wert-Paare gehören, ist der Ansatz, den Sie wahrscheinlich verwenden möchten.

Eine Lösung besteht darin, eine Versionsnummer als einen der Feldwerte anzugeben. Wenn neue Felder hinzugefügt, geändert oder entfernt werden, kann die Version geändert werden.

Beim Deserialisieren der Daten können Sie für jede Version verschiedene Deserialisierungshandler verwenden, die zum Konvertieren von Daten von einer Version in eine andere verwendet werden können.

2

Wie über die Standard-Java Beans Persistenzmechanismus:

java.beans.XMLEncoder 
java.beans.XMLDecoder 

Diese können Java POJOs von XML erstellen (die XML beibehalten wurden). Aus dem Gedächtnis, sieht es (etwas) wie ...

<object class="java.util.HashMap"> 
    <void method="put"> 
     <string>Hello</string> 
     <float>1</float> 
    </void> 
</object> 

Sie haben PersistenceDelegate Klassen zur Verfügung zu stellen, so dass er weiß, wie benutzerdefinierte Klassen bestehen bleiben. Angenommen, Sie entfernen keine öffentlichen Methoden, sind sie gegenüber Schemaänderungen resistent.

12

Sie könnten versuchen Protocol Buffers, es ist ein Open-Source-Projekt von Google, es soll schnell sein (generiert kürzere serialisierte Form als XML und arbeitet schneller). Es behandelt auch das Hinzufügen eines neuen Felds sanft (fügt Standardwerte ein).

0

Haben Sie sich JAXB angesehen? Dies ist ein Mechanismus, mit dem Sie eine Suite von Java-Objekten definieren können, die aus einem XML-Schema erstellt werden. Es ermöglicht Ihnen, von einer Objekthierarchie zu XML zu mappen oder das XML zurück in eine Objekthierarchie zu masern.

0

Ich werde zweiten Vorschlag JAXB oder möglicherweise XStream zu verwenden (früher ist schneller, letzteres hat mehr Fokus auf Objekt Serialisierung Teil). Plus, ich werde vorschlagen, eine anständige JSON-basierte Alternative, Jackson (http://jackson.codehaus.org/Tutorial), die Beeris serserisieren/deserialize JSON-Text in der Spalte speichern kann.

Oh, und ich stimme absolut darin überein, dass keine Java-Binär-Serialisierung unter keinen Umständen für langfristige Datenspeicherung verwenden. Gleiches gilt für Protokollpuffer; beide sind zu empfindlich für diesen Zweck (sie sind besser für den Datentransfer zwischen stark gekoppelten Systemen).

1

Wenn Sie ein Trennzeichen verwenden Sie ein Zeichen verwenden können, die Sie wissen, würden die Daten in die Datenbank nie in Ihrem Text auftreten wie \ 0, oder Sonderzeichen http://unicode.org/charts/symbols.html

jedoch die Zeit, das Senden verbracht und es persistierenden ist wahrscheinlich viel größer als die Kosten der Serialisierung. Daher würde ich vorschlagen, mit etwas Einfachem und Einfachem zu beginnen (wie XStream) und zu schauen, wo Ihre Anwendung die meiste Zeit verbringt und diese optimiert.

0

Sie könnten versuchen Preon. Preon zielt darauf ab, binär kodierte Daten zu sein, was Hibernate zu relationalen Datenbanken und JAXB zu XML ist.

Verwandte Themen