Wie ich db4o in einem industriellen System abgelehnt habe

Bild


Wir sind eine große Unternehmensabteilung, die ein wichtiges Java SE / MS SQL / db4o-System entwickelt. Für einige Jahre wechselte das Projekt von einem Prototyp zu einem industriellen Betrieb und db4o wurde zu einer Berechnungsbremse. Ich wollte von db4o zu moderner noSQL-Technologie wechseln. Versuch und Irrtum führten weit vom ursprünglichen Plan weg - db4o wurde erfolgreich aufgegeben, jedoch auf Kosten eines Kompromisses. Unter der Katze Reflexionen und Implementierungsdetails.


Ist die db4o-Technologie tot?


Auf Habré finden sich nicht so viele Publikationen zu db4o. Bei Stackoverflow ist eine Art Restaktivität wie ein neuer Kommentar zu einer alten Frage oder eine neue unbeantwortete Frage . Wiki glaubt allgemein , dass die aktuelle stabile Version von 2011 ist.


Dies bildet einen allgemeinen Eindruck: Die Technologie ist irrelevant. Es gab sogar eine offizielle Bestätigung : Actian beschloss, das kommerzielle db4o-Produktangebot für Neukunden nicht mehr aktiv zu verfolgen und zu bewerben.


Wie wurde db4o berechnet?


Der Artikel Einführung in objektorientierte Datenbanken befasst sich mit dem Hauptmerkmal von db4o - dem völligen Fehlen eines Datenschemas. Sie können jedes Objekt erstellen


User user1 = new User("Vasya", "123456", 25); 

und dann schreiben Sie es einfach in die Datenbankdatei


 db.Store(user1) 

Das aufgezeichnete Objekt kann dann mit der Methode Query.execute () in der Form abgerufen werden, in der es gespeichert wurde.


Dies ermöglichte es zu Beginn des Projekts, die Anzeige des Audit-Trails mit allen übermittelten Daten schnell sicherzustellen, ohne sich um die Struktur relationaler Tabellen zu kümmern. Dies half dem Projekt zu überleben. Dann befanden sich nur wenige Ressourcen in der Sandbox, und unmittelbar nach dem Ende der heutigen Berechnung wurden Daten für morgen in MS SQL geladen. Alles änderte sich ständig - finden Sie heraus, was genau nachts automatisch serviert wurde. Auf die db4o-Datei kann zugegriffen werden
Extrahieren Sie beim Debuggen einen Schnappschuss des gewünschten Tages und beantworten Sie die Frage "Wir haben alle Daten übermittelt, aber Sie haben nichts bestellt."


Im Laufe der Zeit verschwand das Überlebensproblem, das Projekt startete, die Arbeit mit Benutzeranfragen hat sich geändert. Öffnen Sie eine db4o-Datei beim Debuggen und analysieren Sie eine schwierige Frage eines Entwicklers, der immer beschäftigt ist. Stattdessen gibt es eine Menge von Analysten, die mit einer Beschreibung der Auftragslogik ausgestattet sind und nur den vom Benutzer sichtbaren Teil der Daten verwenden können. Bald wurde db4o nur noch verwendet, um den Verlauf der Berechnung anzuzeigen. Genau wie bei Pareto liefert ein kleiner Teil der Funktionen die Hauptlast.


Im Kampfbetrieb dauert die Verlaufsdatei ~ 35 GB / Tag, das Entladen dauert etwa eine Stunde. Die Datei selbst wird gut komprimiert (1:10), aber aus irgendeinem Grund führt die Bibliothek com.db4o.ObjectContainer keine Komprimierung durch. Im Norden von CentOS schreibt / liest die Bibliothek com.db4o.query.Query eine Datei ausschließlich in einen Stream. Geschwindigkeit ist ein Engpass.


Schematische Darstellung des Gerätes


Das Informationsmodell des Systems ist die Hierarchie der Objekte A, B, C und D. Die Hierarchie ist kein Baum, für den Betrieb sind Verknüpfungen C1 -> B1 erforderlich.


 ROOT || | ==>A1 | || | | ==> B1 <------ | | || | | | | ======> C1 | | | | | | | ===> C1.$D | | =======> C2 | | | | ==> B2 ==> C2.$D | | ===>A2 =======> C3 | | ==> B3 ===> C3.$D | ======> C4 | ===> C4.$D 

Der Benutzer interagiert mit dem Server über die Benutzeroberfläche (GUI), die von com.sun.net.httpserver.HttpsServer bereitgestellt wird. Der Client und der Server tauschen XML-Dokumente aus. Bei der ersten Anzeige weist der Server der Benutzerebene eine Kennung zu, die sich nicht weiter ändert. Wenn der Benutzer einen Verlauf einer bestimmten Ebene benötigt, sendet die GUI dem Server eine XML-umschlossene Kennung. Der Server ermittelt die Werte der Schlüssel zum Durchsuchen der Datenbank, durchsucht die db4o-Datei nach dem gewünschten Tag und ruft das angeforderte Objekt im Speicher sowie alle Objekte ab, auf die er verweist. Erstellt eine XML-Präsentation der extrahierten Ebene und gibt sie an den Client zurück.


Beim Scannen einer Datei liest db40 standardmäßig alle untergeordneten Objekte bis zu einer bestimmten Tiefe und extrahiert eine ziemlich große Hierarchie zusammen mit dem gewünschten Objekt. Die Lesezeit kann reduziert werden, indem die minimale Aktivierungstiefe für die unnötige Foo-Klasse mit conf.common (). ObjectClass (Foo.class) .maximumActivationDepth (1) festgelegt wird.


Die Verwendung anonymer Klassen führt zur Erstellung impliziter Verweise auf die einschließende Klasse this $ 0 . Db4o verarbeitet und stellt solche Links korrekt (aber langsam) wieder her.


0. Idee


Administratoren haben also einen seltsamen Gesichtsausdruck, wenn es darum geht, db4o zu unterstützen oder zu verwalten. Die Datenextraktion ist langsam, die Technologie nicht sehr lebendig. Aufgabe: Wenden Sie anstelle von db4o die aktuelle NoSQL-Technologie an. Ein Paar Spring Data + MongoDB fiel mir auf.


1. Frontaler Ansatz


Mein erster Gedanke war, org.springframework.data.mongodb.core.MongoOperations und die save () -Methode zu verwenden, da sie wie com.db4o.ObjectContainer.db.Store (user1) aussieht. Die MongoDB-Dokumentation besagt, dass Dokumente in Sammlungen gespeichert sind. Es ist logisch, die erforderlichen Systemobjekte als Dokumente der entsprechenden Sammlungen darzustellen. Es gibt auch @ DBRef-Annotationen , mit denen Sie Beziehungen zwischen Dokumenten im Allgemeinen im Sinne von 3NF implementieren können. Lass uns gehen.


1.1. Entladen. Schlüsselreferenztyp


Das System besteht aus POJO-Klassen, die vor langer Zeit und ohne Berücksichtigung all dieser neuen Technologien entwickelt wurden. Felder vom Typ Map <POJO, POJO> werden verwendet, es gibt eine verzweigte Logik, mit ihnen zu arbeiten. Ich speichere dieses Feld, ich erhalte eine Fehlermeldung


 org.springframework.data.mapping.MappingException: Cannot use a complex object as a key value. 

Bei dieser Gelegenheit wurde nur die Korrespondenz von 2011 gefunden , in der vorgeschlagen wurde, einen nicht standardmäßigen MappingMongoConverter zu entwickeln. Bisher habe ich die Problemfelder @ Transient notiert. Es stellte sich heraus, zu sparen und das Ergebnis zu studieren.


Das Speichern erfolgt in der Sammlung, deren Name mit dem Namen der gespeicherten Klasse übereinstimmt. Ich habe noch keine @ DBRef-Anmerkungen verwendet, daher gibt es nur eine Sammlung. JSON-Dokumente sind ziemlich groß und verzweigt. Ich stelle fest, dass MongoOperations beim Speichern des Objekts alle (einschließlich geerbten) nicht leeren Links durchläuft und sie als angehängtes Dokument schreibt.


1.2. Entladen. Benanntes Feld oder Array?


Das Systemmodell ist so, dass die Klasse C mehrmals einen Verweis auf dieselbe Klasse D enthalten kann. In einem separaten defaultMode-Feld und unter anderen Links in ArrayList, so etwas

 public class C { private D defaultMode; private List<D> listOfD = new ArrayList<D>(); public class D { .. } public C(){ this.defaultMode = new D(); listOfD.add(defaultMode); } } 

Nach dem Entladen verfügt das JSON-Dokument über zwei Kopien: ein angehängtes Dokument mit dem Namen defaultMode und ein unbenanntes Element des Dokumentarrays. Im ersten Fall kann auf das Dokument über den Namen zugegriffen werden, im zweiten über den Namen des Arrays mit einem Index. In beiden Fällen können Sie MongoDB-Sammlungen durchsuchen. Ich habe nur mit Spring Data und MongoDB gearbeitet und bin zu dem Schluss gekommen, dass Sie ArrayList verwenden können, wenn Sie es sorgfältig verwenden. Ich habe die Einschränkungen bei der Verwendung von Arrays nicht bemerkt Funktionen wurden später auf der Ebene von MongoDB Connector for BI angezeigt.


1.3. Herunterladen Konstruktorargumente


Ich versuche, ein gespeichertes Dokument mit der Methode MongoOperations.findOne () zu lesen. Das Laden von Objekt A aus der Datenbank löst eine Ausnahme aus


 "No property name found on entity class A to bind constructor parameter to!" 

Es stellte sich heraus, dass die Klasse ein corpName-Feld und der Konstruktor einen String name-Parameter hat und this.corpName = name im Konstruktorkörper zugewiesen ist. MongoOperations erfordert, dass die Feldnamen in den Klassen mit den Namen der Konstruktorargumente übereinstimmen. Wenn mehrere Konstruktoren vorhanden sind, müssen Sie einen mit der Annotation @PersistenceConstructor auswählen. Ich bringe die Namen der Felder und Parameter in Übereinstimmung.


1.4. Herunterladen Mit $ D und diesem $ 0


Die inner verschachtelte Klasse D kapselt das Standardverhalten der Klasse C und ist getrennt von Klasse C nicht sinnvoll. Für jede Instanz von C wird eine Instanz von D erstellt und umgekehrt. Für jede Instanz von D gibt es eine Instanz von C, die sie generiert hat. Die Klasse D verfügt weiterhin über Nachkommen, die alternative Verhaltensweisen implementieren und in listOfD gespeichert werden können. Der Konstruktor der Nachkommenklassen von D benötigt das Vorhandensein eines bereits vorhandenen Objekts C.


Zusätzlich zu verschachtelten inneren Klassen verwendet das System anonyme innere Klassen. Wie Sie wissen , enthalten beide einen impliziten Verweis auf eine Instanz einer einschließenden Klasse. Das heißt, als Teil jeder Instanz des CD-Objekts erstellt der Compiler einen Link mit diesem Wert von $ 0, der auf das übergeordnete Objekt C verweist.


Ich versuche erneut, das gespeicherte Dokument aus der Sammlung zu lesen und eine Ausnahme zu erhalten


 "No property this$0 found on entity class $D to bind constructor parameter to!" 

Ich erinnere mich, dass die Methoden der Klasse D die volle Kraft der C.this.fieldOfClassC-Referenzen verwenden und die Nachkommen der Klasse D erfordern, dass der Konstruktor C als Argument instanziiert. Das heißt, ich muss eine bestimmte Reihenfolge zum Erstellen von Objekten in MongoOperations angeben, damit das übergeordnete Objekt C im D-Konstruktor angegeben werden kann. Wieder der nicht standardmäßige MappingMongoConverter?


Vielleicht keine anonymen Klassen verwenden und innere Klassen normalisieren? Die Architektur eines bereits implementierten Systems zu verfeinern oder vielmehr zu verfeinern, ist eine Wow-Aufgabe ...


2. Annäherung von 3NF / @ DBRef


Ich versuche andererseits, jede Klasse in meiner Sammlung zu speichern und im Geiste von 3NF Verbindungen zwischen ihnen herzustellen.


2.1. Entladen. @DBRef ist wunderschön


Klasse C enthält mehrere Verweise auf D. Wenn die Links defaultMode und ArrayList als @DBRef markiert sind, verringert sich die Dokumentgröße, anstatt großer angehängter Dokumente werden saubere Links angezeigt. Im Feld json Dokument der Sammlung C wird das Feld angezeigt

 "defaultMode" : DBRef("D", ObjectId("5c496eed2c9c212614bb8176")) 

In der MongoDB-Datenbank wird automatisch eine Sammlung D und ein Dokument mit einem Feld darin erstellt


 "_id" : ObjectId("5c496eed2c9c212614bb8176") 

Alles ist einfach und schön.


2.2. Herunterladen Klasse-D-Konstruktor


Bei der Arbeit mit Links weiß das C-Objekt, dass das Standard-D-Objekt genau einmal erstellt wird. Wenn Sie alle D-Objekte außer dem Standardobjekt umgehen müssen, vergleichen Sie einfach die Links:


 private D defaultMode; private ArrayList<D> listOfD; for (D currentD: listOfD){ if (currentD == defaultMode) continue; doSomething(currentD); } 

Ich rufe findOne () auf, lerne meine Klasse C. Es stellt sich heraus, dass MongoOperations ein JSON-Dokument liest und den D-Konstruktor für jede @ DBRef-Annotation aufruft, auf die es stößt, jedes Mal, wenn ein neues Objekt erstellt wird. Ich erhalte ein seltsames Konstrukt - zwei verschiedene Verweise auf D im Feld defaultMode und im Array listOfD, wobei der Link identisch sein sollte.


Von der Community lernen: "Dbref sollte meiner Meinung nach bei der Arbeit mit Mongodb vermieden werden." Eine weitere Überlegung in der gleichen Weise wie in der offiziellen Dokumentation: Das denormalisierte Datenmodell, in dem verwandte Daten in einem einzelnen Dokument gespeichert sind, ist optimal, um DBRefs aufzulösen. Ihre Anwendung muss zusätzliche Abfragen ausführen, um die referenzierten Dokumente zurückzugeben.


Auf der erwähnten Dokumentationsseite steht ganz am Anfang: "Für viele Anwendungsfälle in MongoDB ist das denormalisierte Datenmodell, bei dem verwandte Daten in einem einzigen Dokument gespeichert sind, optimal." Ist es für mich geschrieben?


Wenn Sie sich auf den Designer konzentrieren, müssen Sie nicht wie in einem relationalen DBMS denken. Die Wahl ist:


  • Wenn Sie @DBRef angeben:
    • Der Konstruktor für jede Annotation wird aufgerufen und mehrere identische Objekte werden erstellt.
    • MongoOperations findet und liest alle Dokumente aus allen zugehörigen Sammlungen. ObjectId fordert den Index an und liest dann aus vielen Sammlungen einer (großen) Datenbank.
  • Wenn Sie nichts angeben, wird der "abnormalisierte" JSON mit Wiederholungen derselben Daten gespeichert.

Ich stelle für mich selbst fest: Sie können sich nicht auf @DBRef verlassen, sondern ein Feld vom Typ ObjectId verwenden und es manuell ausfüllen. In diesem Fall anstelle von


 "defaultMode" : DBRef("D", ObjectId("5c496eed2c9c212614bb8176")) 

JSON-Dokument enthält


 "defaultMode" : ObjectId("5c496eed2c9c212614bb8176") 

Es wird nicht automatisch geladen - MongoOperations weiß nicht, in welcher Sammlung nach einem Dokument gesucht werden soll. Das Dokument muss in eine separate (verzögerte) Anforderung geladen werden, die die Sammlung und die Objekt-ID angibt. Eine einzelne Abfrage sollte das Ergebnis schnell zurückgeben. Außerdem wird für jede Sammlung von ObjectId ein automatischer Index erstellt.


2.3. Also was jetzt?


Zwischensummen. Es war nicht möglich, die db4o-Funktionalität schnell und einfach in MongoDB zu implementieren:


  • Es ist unklar, wie ein benutzerdefiniertes POJO als Schlüssel - Wert - Listenschlüssel verwendet wird.
  • Es ist unklar, wie die Reihenfolge festgelegt wird, in der Objekte in MappingMongoConverter erstellt werden.
  • Es ist unklar, ob ein "nicht normalisiertes" Dokument ohne DBRef hochgeladen werden soll und ob ein eigener Mechanismus für die verzögerte Initialisierung erforderlich ist.

Sie können Lazy Loading hinzufügen. Sie können versuchen, MappingMongoConverter auszuführen. Sie können vorhandene Konstruktoren / Felder / Listen ändern. Aber es gibt viele Jahre der Überlagerung von Geschäftslogik - keine schwache Änderung und das Risiko, niemals getestet zu werden.


Kompromisslösung: Erstellen eines neuen Mechanismus zum Speichern von Daten für das zu lösende Problem unter Beibehaltung des Mechanismus für die Interaktion mit der GUI.


3. Der dritte Versuch, die Erfahrung der ersten beiden


Pareto schlägt vor, dass das Lösen von Problemen mit der Geschwindigkeit der Benutzer den Erfolg der gesamten Aufgabe bedeuten wird. Die Aufgabe lautet wie folgt: Sie müssen lernen, wie Sie Benutzerpräsentationsdaten ohne db4o schnell speichern und wiederherstellen können.


Dadurch wird die Möglichkeit verloren, das gespeicherte Objekt beim Debuggen zu untersuchen. Einerseits ist das schlecht. Auf der anderen Seite treten solche Aufgaben selten auf, und in git sind alle Kampflieferungen markiert. Aus Gründen der Fehlertoleranz serialisiert das System die Berechnung jedes Mal vor dem Entladen in eine Datei. Wenn Sie ein Objekt beim Debuggen untersuchen müssen, können Sie die Serialisierung durchführen, die entsprechende Systemassembly klonen und die Berechnung wiederherstellen.


3.1. Benutzerdefinierte Präsentationsdaten


Um Präsentationen von Benutzerebenen zu erstellen, verfügt das System über eine spezielle Viewer-Klasse. Die Viewer.getXML () -Methode empfängt eine Ebene als Eingabe, extrahiert die erforderlichen numerischen Werte und Zeichenfolgenwerte daraus und generiert XML.


Wenn der Benutzer aufgefordert hat, die Ebene der heutigen Berechnung anzuzeigen, wird die Ebene im RAM gefunden. Um eine Berechnung aus der Vergangenheit anzuzeigen, findet die Methode com.db4o.query.Query.execute () die Ebene in der Datei. Die Ebene aus der Datei unterscheidet sich fast nicht von der gerade erstellten Ebene, und Viewer erstellt die Präsentation, ohne die Ersetzung zu bemerken.


Um mein Problem zu lösen, benötige ich einen Vermittler zwischen der Berechnungsebene und ihrer Präsentation - das Präsentationsframework (Frame), das Daten speichert und auf den verfügbaren XML-Daten aufbaut. Die Aktionskette zum Erstellen der Präsentation wird jedes Mal länger, wenn ein Frame generiert wird und der Frame XML generiert:


  : < > -> Viewer.getXML() : < > -> Viewer.getFrame() -> Frame.getXML() 

Wenn Sie die Story speichern, müssen Sie Frames aller Ebenen erstellen und in die Datenbank schreiben.


3.2. Entladen


Die Aufgabe war relativ einfach und es gab keine Probleme damit. Der Frame wiederholte die Struktur der XML-Präsentation und erhielt ein rekursives Gerät in Form einer Hierarchie von Elementen mit den Feldern String, Integer und Double. Der Frame fordert getXML () von allen seinen Elementen an, sammelt es in einem einzigen Dokument und gibt es zurück. MongoOperations hat mit der rekursiven Natur des Frames großartige Arbeit geleistet und im weiteren Verlauf keine neuen Fragen gestellt.


Endlich ging alles los! Die WiredTiger-Engine komprimiert standardmäßig MongoDB-Dokumentensammlungen. Im Dateisystem dauerte das Entladen ca. 3,5 GB pro Tag. Ein zehnfacher Rückgang gegenüber db4o ist nicht schlecht.


Zunächst wurde das Entladen einfach angeordnet - eine rekursive Durchquerung des Ebenenbaums MongoOperations.save () für jeden. Das Entladen dauerte 5,5 Stunden, und dies trotz der Tatsache, dass beim Erstellen von Präsentationen nur Objekte gelesen werden. Ich füge Multithreading hinzu: Durchlaufe rekursiv den Ebenenbaum, teile alle verfügbaren Ebenen in Pakete einer bestimmten Größe auf, erstelle Callable.call () -Implementierungen entsprechend der Anzahl der Pakete, übertrage jedes Paket in unser eigenes Paket und erledige alles über ExecutorService.invokeAll ().


MongoOperations stellte erneut keine Fragen und leistete im Multithread-Modus hervorragende Arbeit. Wählen Sie die Größe des Pakets empirisch aus, um die beste Entladegeschwindigkeit zu erzielen. Es stellte sich heraus, 15 Minuten für ein Paket von 1000 Ebenen.


3.3. Mongo BI Connector oder wie Leute damit arbeiten


Die MongoDB- Abfragesprache ist groß und leistungsstark. Ich habe unweigerlich Erfahrungen damit gesammelt und diesen Ort erreicht. Die Konsole unterstützt JavaScript, Sie können schöne und leistungsstarke Designs schreiben. Das ist eine Seite. Auf der anderen Seite kann ich einer guten Hälfte der Analystenkollegen mit einer Anfrage das Gehirn brechen


 db.users.find( { numbers: { $in: [ 390, 754, 454 ] } } ); 

statt des üblichen


 SELECT * FROM users WHERE numbers IN (390, 754, 454) 

MongoDB Connector für BI hilft Ihnen dabei, Sammlungsdokumente in tabellarischer Form darzustellen. Die MongoDB-Datenbank wird als dokumentbasierte Datenbank bezeichnet. Sie kann keine Hierarchie von Feldern / Dokumenten in tabellarischer Form darstellen. Damit der Connector funktioniert, muss die Struktur der zukünftigen Tabelle in einer separaten DRDL-Datei beschrieben werden, deren Format yaml sehr ähnlich ist. In der Datei müssen Sie die Entsprechung zwischen dem Feld der relationalen Tabelle an der Ausgabe und dem Pfad zum Feld des JSON-Dokuments an der Eingabe angeben.


3.4. Funktionen mit Arrays


Es wurde oben gesagt, dass es für MongoDB selbst keinen besonderen Unterschied zwischen einem Array und einem Feld gibt. Aus Connector-Sicht unterscheidet sich ein Array stark von einem benannten Feld. Ich musste sogar die fertige Frame-Klasse umgestalten. Ein Array von Dokumenten sollte nur verwendet werden, wenn ein Teil der Informationen in eine verknüpfte Tabelle eingefügt werden muss.


Wenn das JSON-Dokument eine Hierarchie benannter Felder ist, kann auf jedes Feld zugegriffen werden, indem der Pfad vom Dokumentstamm durch einen Punkt angegeben wird, z. B. xy. Wenn die Entsprechung xy => fieldXY in der DRDL-Datei angegeben ist, enthält die Ausgabetabelle so viele Zeilen, wie Dokumente in der Sammlung vorhanden sind am Eingang. Wenn in einem Dokument kein xy-Feld vorhanden ist, befindet sich NULL in der entsprechenden Zeile der Tabelle.


Angenommen, wir haben eine MongoDB-Datenbank namens Frames, die Datenbank enthält eine Sammlung A, und MongoOperations hat zwei Instanzen der Klasse A in diese Sammlung geschrieben. Dies sind die Dokumente: erstens


 { "_id": ObjectId("5cdd51e2394faf88a01bd456"), "x": { "y": "xy string value 1"}, "days": [{ "k": "0", "v": 0.0 }, { "k": "1", "v": 0.1 }], "_class": "A" } 

und zweitens (ObjectId unterscheidet sich durch die letzte Ziffer):


 { "_id": ObjectId("5cdd51e2394faf88a01bd457"), "x": { "y": "xy string value 2"}, "days": [{ "k": "0", "v": 0.3 }, { "k": "1", "v": 0.4 }], "_class": "A" } 

Der BI-Connector kann nicht über den Index auf die Elemente des Arrays zugreifen, und es ist einfach unmöglich, beispielsweise das Feld days [1] .v aus dem Array in die Tabelle zu extrahieren. Stattdessen kann der Connector jedes Element des Days-Arrays mit dem Operator $ unwind als Zeile in einer separaten Tabelle darstellen. Diese separate Tabelle wird über die Zeilen-ID der ursprünglichen Eins-zu-Viele-Beziehung zugeordnet. In unserem Beispiel sind die Tabellen tableA für Sammlungsdokumente und tableA_days für Dokumente des Tagesarrays definiert. Die DRDL-Datei sieht folgendermaßen aus:


 schema: - db: Frames tables: - table: tableA collection: A pipeline: [] columns: - Name: _id MongoType: bson.ObjectId SqlName: _id SqlType: objectid - Name: xy MongoType: string SqlName: fieldXY SqlType: varchar - table: tableA_days collection: A pipeline: - $unwind: path: $days columns: - Name: _id #   MongoType: bson.ObjectId SqlName: tableA_id SqlType: objectid - Name: days.k MongoType: string SqlName: tableA_dayNo SqlType: varchar - Name: days.v MongoType: string SqlName: tableA_dayVal SqlType: varchar 

Der Inhalt der Tabellen lautet: table tableA


_idfieldXY
5cdd51e2394faf88a01bd456xy String Wert 1
5cdd51e2394faf88a01bd457xy String Wert 2

und Tabelle tableA_days


tableA_idtableA_dayNotableA_dayVal
5cdd51e2394faf88a01bd45600.0
5cdd51e2394faf88a01bd45610,1
5cdd51e2394faf88a01bd45700,3
5cdd51e2394faf88a01bd45710,4

Insgesamt


Es war nicht möglich, die Aufgabe in der ursprünglichen Formulierung zu implementieren. Sie können db4o nicht einfach durch MongoDB ersetzen. MongoOperations kann kein Objekt wie db4o automatisch wiederherstellen. Sie können dies wahrscheinlich tun, aber die Arbeitskosten sind nicht mit dem Aufrufen der Speicher- / Abfragemethoden der db4o-Bibliothek vergleichbar.


Audit Trail. Db4o ist ein sehr nützliches Werkzeug zu Beginn eines Projekts. Sie können das Objekt einfach schreiben, dann wiederherstellen und gleichzeitig keine Sorgen und Tabellen machen. All dies mit einer wichtigen Einschränkung: Wenn Sie die Hierarchie der Klassen ändern müssen (Klasse E zwischen A und B hinzufügen), werden alle zuvor gespeicherten Informationen unlesbar. Für das Starten eines Projekts ist dies jedoch nicht sehr wichtig, solange keine große Anzahl alter Dateien vorhanden ist.


Wenn genügend Erfahrung mit MongoOperations vorhanden war, verursachte das Schreiben des Uploads keine Probleme. Das Schreiben eines neuen Codes für das Framework ist viel einfacher als das Wiederherstellen des alten Codes, der ebenfalls in Produktion geht.

Source: https://habr.com/ru/post/de461417/


All Articles