Zum Inhalt springen

Db4o

aus Wikipedia, der freien Enzyklopädie
Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 24. Juni 2007 um 17:27 Uhr durch Edlich (Diskussion | Beiträge) (Grundlegende API). Sie kann sich erheblich von der aktuellen Version unterscheiden.

db4o (Database for Objects) ist eine Objektdatenbank für Java und .NET. db4o zeichnet sich durch einen recht kleinen Footprint von etwa 600KB aus und eignet sich dadurch für die Einbettung in andere Programme und für Umgebungen mit knappem Speicher, wie beispielsweise PDAs.

db4o läuft nativ auf Javas JDK 1.1.x bis 6.0. Daneben werden alle Sprachen unterstützt, die auf der CLR von .NET aufsetzen. Beispielsweise C# und VB.NET. Dadurch kann db4o ebenfalls als Server unter Windows und UNIX laufen.

Bekannte Firmen, die db4o einsetzen, sind:

  • BMW: Zur Aufzeichnung von Fahrzeugdaten
  • Bosch: Persistenz für Bosch Roboter, die Verpackungen für Nahrungsmittel in aller Welt produzieren und ständig neu konfiguriert werden müssen.
  • Indra: Echtzeit Datenerfassung in den Spanischen Hochgeschwindigkeitszügen.
  • Energieunternehmen / Deutsche_Post: Hier wird db4o für die Datenfassung auf Clients wie Handhelds verwendet.
  • weitere Unternehmen: Seagate, Intel, Ricoh, Boeing und viele weitere

Systemeigenschaften und Objektmanagement

  • Neben dem kleinen Footprint ist auch der Verbrauch an RAM gering und überschreitet 1MB in der Regel nicht.
  • Db4o kann nicht von aussen administriert werden. Sämtliche Einstellungen müssen über den Code vorgenommen werden.
  • Die Datenbank kann auch in gemischen Umgebungen eingesetzt werden. Also zwei Anwendungen unter z.B. C# oder Java können auf eine Java oder C# Datenbank zugreifen. Mit Hilfe von Aliasen können sich dabei sogar die Klassennamen und Packages unterscheiden.
  • Eine der wichtigsten Vorteile von db4o: Objekte können einfach so gespeichert werden. Es ist keine Vererbung, kein Ableitung von speziellen Interfaces, kein [[Aspektorientierte_Programmierung|AOP] mäßiges Bytecode enhancement nötig. Das Objekt kann dabei beliebige Typen enthalten und zudem beliebig tief sein. Also Objekte in Objekten in Objekten etc. enthalten.
  • Mit dieser Eigenschaft ist es möglich, Objektinstanzen in weniger als 2 Minuten zu speichern. Inklusive Download und das jar / dll in den Classpath zu nehmen.

Grundlegende API

Unter API versteht man das Application Programming Interface, d.h. die Programmierschnittstelle, mit der der Entwickler die Datenbank programmiert. Dabei zeigt sich, dass der Unterschied zu anderen Programmen wie Hibernate oder JPA / EJB nicht allzu groß ist.

Ein einfaches Codebeispiel, das zusammenhängend ausgeführt werden sollte:

   ObjectContainer db = Db4o.openFile("C:/beispiel.db");
   try { // Speichert zwei Objekte
      db.set(new Person("John Doe","TOP INC",45));
      db.set(new Person("Clara Himmel","BB Radio",30));
      
      ObjectSet result = db.get(new Person());
      while (result.hasNext()) { // Iteriere durch alle Objekte 
          System.out.println(result.next());
      }
      
      result = db.get(new Person("Clara Himmel"));
      Person found = (Person) result.next();
      found.setAge(25); // Wurde jünger
      db.set(found); // Objekt updaten
      db.delete(found); // Objekt löschen
      db.commit();
   }
   finally {
      db.close();
   }
  • Ähnlich zu EJB / JPA (dort EntityManager) erstellt man einen ObjektContainer. Der kann hier entweder auf eine Datei verweisen, oder ein Server- oder Client-Container sein. Im ersten Fall werden alle Datein in einer Datei gespeichert.
    • Nachteil: Die Daten sind also nicht komplett unabhängig von der Klasse der Programmiersprache. Das Format ist proprietär und kann ggf. von nachfolgenden Programmiersprachen nicht mehr so einfach gelesen werden.
    • Vorteil: Diese kann dan sehr leicht zwischen Firmen ausgetauscht werden. Der Datenzugriff ist sehr schnell.

Danach werden alle CRUD (Create, Read, Update und Delete) Operationen ausgeführt:

  • CREATE: Mit db.set(object) wird ein beliebiges Objekt gespeichert. Dies ist analog zum JPA Standard, wo man em.persist(object) aufruft. Allerdings muss man in letzterem Fall das Domain Objekt mindestens mit @Entity annotiert oder in XML registriert / gemappt haben.
  • READ: Es folgt eine einfache Suche mit der einfachsten Abfragesprache (s.u.) Query by Example. Eine Personinstanz wird als Template erstellt und beliebige Felder werden gesetzt. Zurückgegeben werden alle Objekt in der Datenbank, bei denen die Felder passen. found enthält daher das vollständige Objekt, das oben gespeichert wurde.
  • UPDATE: Dieses found Objekt wird jetzt intern referenziert und kann daher verändert .setAge(25)und nochmals gespeichert werden. Dann ist es aktualisiert. Im JPA Standard entspeicht dies einem em.merge(object), wobei das Objekt immer attached, also von der Session referenziert "gemerkt" werden muss.
  • DELETE: db.delete(object) löscht ein Objekt, das dem Objektmanager bekannt sein muss.

Abfragesprachen

Db4o bietet drei Abfragesprachen, die alle nicht allzuweit von dem Entfert sind, was Hibernate und JPA / EJB bieten:

Query By Example (QBE)

Query By Example Query_by_Example steht für Suche mit einem Template Muster. Die Grundlagen dafür wurden schon in den 70er jahren von Moshé M. Zloof in einigen Artikel gelegt. en:Hibernate_(Java) und db4o bieten dies in einer leicht abgeschwächten Version an.

Bei db4o kann wie oben gezeigt ein beliebiges Objekt erstellt werden. Danach wird entweder:

  • Kein Feld gesetzt, so dass alle Felder null sind. Oder es wird direkt eine Referenz auf die Klasse übergeben (z.B. Person.class). In diesem Fall werden alle in der DB gespeicherten Instanzen zurückgeliefert.
  • Es werden beliebig viele Felder gesetzt: Dann werden alle Objekte zurückgeliefert, bei denen das Template Objekt passt.
  • Es wird null übergeben. Dann werden alle Objekte aus der Datenbank zurückgeliefert.

Native Queries

Native Queries sind Abfragen in der Programmiersprache selbst. Also bei db4o z.B. in Java oder C#.

  • Vorteile: 1. Der Programmierer muss keine neue Sprache lernen (SQL). 2. Die Abfragen sind typsicher und 3. Refactoringfest. Fehler in Query Strings wie bei SQL werden daher nicht so leicht möglich und werden früh gefunden.
  • Nachteil: Die Erstellung der Abfrage ist jetzt komplett in der Hand der Entwickler und z.B. nicht in der Hand von Administratoren, die wie bei "Stored-Procedures" ein "Sicherheits-"Auge auf die Datenbank werfen. Weiterhin sind Native Queries nicht so mächtig wie entsprechende Konstrukte in anderen Abfragesprachen wie HQL oder JPQL, da hier im String mehr Schlüsselwörter (wie z.B. für Aggregations) zur Verfügung stehen.

Native Queries wurden z.B. in den untenstehenden Quellen beschrieben.

Dazu Beispiele in C# 3.0(Beispiele in Java sind unter der db4o Community Dokumentationsseite zu finden): var persons = db.Query<Person> (s => s.Age < 50); Entscheidend für den komfortablen Einsatz ist, ob und wie die Sprache Closures unterstützt. Ansonsten muss mit inneren Klassen und Anonymous Delegates gearbeitet werden, um mdie Abfrage als freischwebender Code einer Methode zu übergeben.

Der Code von Native Queries wird bei db4o nie ausgeführt, sondern z.B. zur Laufzeit gelesen und dann verarbeitet / ausgeführt.

Zum Vergleich von Native Queries und JPQL oder HQL sei hier auf Microsofts LINQ verwiesen. Microsoft konnte die Sprache verändern und so mächtige Abfragekonstrukte direkt in C# einbetten.

SODA / Criteria Queries

Intern werden Native Queries bei db4o auf SODA abgebildet / transformiert. SODA ist eine Anfragesprache, die schon sehr früh auf Sourceforge gehostet wurde und dort unabhängig weiterentwickelt wurde. Es handelt sich dabei um eine Sprache, bei der Objektbäume erstellt werden, die die Abfrage mittels Objekten einschränken. Sie sind daher mächtiger als Native Queries, aber wiederum schwerer zu erstellen (da der Code schwerer zu lesen ist).

Die SODA Abfragen ähneln denen von Hibernate Criteria Abfragen stark. Ein Beispiel:

  Query query=db.query();
  query.constrain(Person.class);
  query.descend("alter").constrain(50).greater();
  ObjectSet result=query.execute();

Hier wird die Abfrage zunächst auf die Klasse Person eingeschränkt. Danach weiter auf alle Personen, die älter als 50 sind.

Transaktionen

Mit dem öffnen des Containers aus obigem Beispiel wird eine Transaktion erstellt. Diese kann jederzeit mit db.comitt() oder db.rollback auf die Datenbank geschrieben oder zurückgerollt werden. Db4o garantiert dabei ein ACID verhalten. Alles innerhalb einer Transaktion entspricht den ACID Anforderungen. Intern werden dabei alle Zugriffe auf die Datenbank innerhalb der Transaktion serialisiert. Dies hat schwerwiegende Konsequenzen für das Datenbanksystem:

  • Durch das proprietäre Datenformat ist der Zugriff für einen Thread zwar meistens schneller als andere Datenbank / Mapper-Kombinationen.
  • Dennoch skaliert ein "multithreaded" Zugriff nicht, wieder beispielsweise für den Bau von Großportalen nötig ist.

Erfahrungen zufolge sind bis zu einem Dutzend Zugriffe pro Sekunde in der Regel machbar, was auch für viele Web-Portale genügen sollte.

db4o arbeitet wegen den obigen Punkten an einer Serverversion, die auch multithreaded skaliert.

Client- / Server-Modes

Db4o bietet mehrere Arbeitsmodi an:

1. Embedded Mode: Es wird im Anwendungscode ein Objektcontainer eröffnet, wie in obigem Beispiel gezeigt. Basis ist hier ein filebasierter Zugriff.

2. Client / Server Mode: Db4o kann als Server gestartet werden und dann von Clients anfragen entgegen nehmen. Beispiel für den Server:

ObjectServer server = Db4o.openServer("c:/liveserver.db", 8732); server.GrantAccess("user1", "password"); server.GrantAccess("user2", "password"); Hier wird ein Thread geöffnet, der auf Clients listened. Der Server selbst kann über Monitore warten und beispielsweise Statusausgaben machen. Zugriffsrechte können wie bereits erwähnt nicht direkt von aussen mittels einem Tool verwaltet werden. Entweder werden diese im Code angelegt oder per Console etc. eingelesen.

Ein Client würde so aussehen.

aClient = Db4o.OpenClient("196.42.103.142", 8732, "user2", "password");

Mittels eines sogenannter "Out-Of-Band Signalling" Kommunikationsprotokolls können dem Server beliebige Objekte gesendet werden, mit denen ein Server dann administriert werden kann. Z.B. kann die Aufforderung zum Defragmentieren der Datei übermittelt werden.

Replikation

Mittels weniger Zeilen können beliebig viele Server repliziert (geclustert) werden. Dies geschieht mit dem db4o dRS Modul.

Die Objekte bekommen dazu eine eindeutige UUID. Dann können einzelne Objekte oder die gesamte Datenbank uni- oder bidirektional verteilt werden. D.h. jedes neue Objekt wird an alle anderen Datenbanken gesendet. Dies erlaubt es große und redundante Architekturen aufzusetzen.

Sehr interessant ist ebenfalls die Option, eine db4o Datenbank in relationale Datenbanken zu replizieren. Dies bedeutet eine Brücke / Verbindung zu beiden Welten, die oft als getrennt angesehen werden. db4o verwendet dazu Hibernate. Nach der Konfiguration der dRS-Bridge können ebenfalls einzelne Objekte oder ganze Datenbanken per Trigger wahlweise in eine oder beide Richtungen transferiert werden. In vielen Fällen können in der Industrie so die Vorteile beider Welten gut ausgenutzt werden.

Sonstiges

Dieser Abschnitt stellt weitere Features vor, die nicht so einfach zu kategorisieren sind:

Callbacks

Bei db4o gibt es interne und externe Callbacks. Diese ähnen den Datenbank-Tiggern:

  • Interne Callbacks: werden als Methoden den Klassen hinzugefügt. Diese werden dann (ohne jedes Interface) von db4o dynamische per Reflection erkannt und ausgeführt. Verfügbar sind hier aspektähnliche Aufrufe vor und nach speziellen Punkten (analog der Joint-Points bei AOP). z.B. Activate, Deactivate, Delete, New, Update jeweis mit Can oder 'On davor. jenachdem ob die Methode vorher oder nachher aktiviert werden soll.
  • Externe Callbacks: sind nicht Klassen zugeordnet, da diese evtl. nicht geändert werden können oder dürfen. Externe Callbacks werden am ObjektContainer registriert und können dann vor oder nach CRUD Operationen aufgerufen werden.

Callbacks gibt es in vielen großen Datenbankmappern und sind ein sehr mächtiges Werkzeug, um z.B. beim Speichern oder Löschen von Objekten Checks durchzufüren, Defaultwerte zu setzen oder Sicherheitsaspekte zu berücksichtigen.

Lazy Loading

Bei db4o gibt es drei Modi für das Laden von Objekten:

  1. IMMEDIATE: Hier werden bei einer Abfrage alle gesuchten Objekte instanziiert und zurückgeliefert. Bei großen Abfragen (1-10 Mio Objekte) kann das einige Sekunden dauern.
  2. SNAPSHOT: Ein Mischmode. Alle indizierten Teile werden sofort ausgewertet. Nicht Indizierte Abfrageteiler werden erst später ausgewertet.
  3. LAZY: Hier wird sofort ein ObjektSet zurückgeliefert, jedoch ist kein Objekt instanziiert. Ein Thread sucht alle weiteren Ergebnisse. Dies ist ideal, wenn ersteimal die ersten 10 oder 100 Ergebnisse schnell angezeigt werden sollen.

Der letzte Mode ist daher zwar schnell (eine Abfrage mit einigen Dutzend Ergebnisobjekten auf einer Menge von 100.000 Objekten sollte hier in weit weniger als einer Sekunde fertig sein), aber es können Seiteneffekte auftreten: Das Lesen von Daten, die nach der initialen Abfrage geändert wurden.

Lizenz

db4o wird seit 2004 wahlweise unter der GPL als Open Source lizensiert oder unter einer kommerziellen Lizenz, die die Verwendung in nicht-GPL-Projekten erlaubt. Daneben gibt es eine Classpath ähnliche Lizenz, die es erlaubt, db4o in Open-Source Projekte zu integrieren, die nicht db4o / GPL konform sind.

Historie

Das db4o Projekt begann im Jahr 2000 unter Führung von Carl Rosenberger. Entwickelt wird db4o von der Firma db4objects, Inc., die 2004 mit Hilfe von Investoren wie Mark Leslie (VERITAS Software), Vinod Khosla (SUN Microsystems) und Jerry Fiddler (Wind River) gegründet wurde.

Literatur

  • Patrick Römer, Larysa Visengeriyeva, "db4o. schnell + kompakt", Entwickler.Press, 2006
  • Jim Paterson, Stefan Edlich, Henrik Hörning, Reidar Hörning, "The Definitive Guide to db4o", Apress Inc., 2006

Native Queries:

  • William Cook, Carl Rosenberger, "Native Queries for Persistent Objects"
  • William Cook, Siddhartha Rai: Safe Query Objects, 2005

Beide Referenziert auf: http://www.cs.utexas.edu/~wcook

  • LINQ Abfragesprache von Microsoft mit nativen Konstrukten in C#