Gids voor MapDB

1. Inleiding

In dit artikel zullen we kijken naar de MapDB-bibliotheek - een ingebedde database-engine die toegankelijk is via een collectie-achtige API.

We beginnen met het verkennen van de kernlessen DB en DBMaker die helpen bij het configureren, openen en beheren van onze databases. Vervolgens gaan we in op enkele voorbeelden van MapDB-gegevensstructuren die gegevens opslaan en ophalen.

Ten slotte bekijken we enkele van de in-memory-modi voordat we MapDB vergelijken met traditionele databases en Java-verzamelingen.

2. Gegevens opslaan in MapDB

Laten we eerst de twee klassen introduceren die we tijdens deze tutorial constant zullen gebruiken - DB en DBMaker. De DB class staat voor een open database. De methoden roepen acties op voor het maken en sluiten van opslagcollecties om databaserecords af te handelen, evenals om transactiegebeurtenissen af ​​te handelen.

DBMaker behandelt databaseconfiguratie, creatie en opening. Als onderdeel van de configuratie kunnen we ervoor kiezen om onze database in het geheugen of op ons bestandssysteem te hosten.

2.1. Een eenvoudige Hash kaart Voorbeeld

Laten we, om te begrijpen hoe dit werkt, een nieuwe database in het geheugen starten.

Laten we eerst een nieuwe in-memory database maken met de DBMaker klasse:

DB db = DBMaker.memoryDB (). Make ();

Eens onze DB object actief is, kunnen we het gebruiken om een HTreeMap om met onze databaserecords te werken:

String welcomeMessageKey = "Welkomstbericht"; String welcomeMessageString = "Hallo Baeldung!"; HTreeMap myMap = db.hashMap ("myMap"). CreateOrOpen (); myMap.put (welcomeMessageKey, welcomeMessageString);

HTreeMap is MapDB's Hash kaart implementatie. Dus nu we gegevens in onze database hebben, kunnen we deze ophalen met de krijgen methode:

String welcomeMessageFromDB = (String) myMap.get (welcomeMessageKey); assertEquals (welcomeMessageString, welcomeMessageFromDB);

Eindelijk, nu we klaar zijn met de database, moeten we deze sluiten om verdere mutatie te voorkomen:

db.close ();

Om onze gegevens in een bestand op te slaan in plaats van in het geheugen, hoeven we alleen maar de manier te veranderen waarop onze DB object wordt geïnstantieerd:

DB db = DBMaker.fileDB ("file.db"). Make ();

In ons voorbeeld hierboven worden geen typeparameters gebruikt. Als gevolg hiervan zitten we vast aan het casten van onze resultaten om met specifieke typen te werken. In ons volgende voorbeeld introduceren we Serializers om de noodzaak van gieten te elimineren.

2.2. Collecties

MapDB bevat verschillende soorten collectie. Om dit te demonstreren, laten we wat gegevens uit onze database toevoegen en ophalen met behulp van een NavigableSet, wat werkt zoals je zou verwachten van een Java Set:

Laten we beginnen met een simpele concretisering van onze DB voorwerp:

DB db = DBMaker.memoryDB (). Make ();

Laten we vervolgens onze NavigableSet:

NavigableSet set = db .treeSet ("mySet") .serializer (Serializer.STRING) .createOrOpen ();

Hier de serialisator zorgt ervoor dat de invoergegevens uit onze database worden geserialiseerd en gedeserialiseerd met Draad voorwerpen.

Laten we vervolgens wat gegevens toevoegen:

set.add ("Baeldung"); set.add ("is geweldig");

Laten we nu controleren of onze twee verschillende waarden correct aan de database zijn toegevoegd:

assertEquals (2, set.size ());

Laten we tot slot, aangezien dit een set is, een dubbele string toevoegen en controleren of onze database nog steeds maar twee waarden bevat:

set.add ("Baeldung"); assertEquals (2, set.size ());

2.3. Transacties

Net als bij traditionele databases, is het DB class biedt methoden om plegen en terugrollen de gegevens die we aan onze database toevoegen.

Om deze functionaliteit mogelijk te maken, moeten we onze DB met de transactie inschakelen methode:

DB db = DBMaker.memoryDB (). TransactionEnable (). Make ();

Laten we vervolgens een eenvoudige set maken, wat gegevens toevoegen en deze vastleggen in de database:

NavigableSet set = db .treeSet ("mySet") .serializer (Serializer.STRING) .createOrOpen (); set.add ("Een"); set.add ("Twee"); db.commit (); assertEquals (2, set.size ());

Laten we nu een derde, niet-gecommitteerde tekenreeks aan onze database toevoegen:

set.add ("Drie"); assertEquals (3, set.size ());

Als we niet tevreden zijn met onze gegevens, kunnen we de gegevens terugdraaien met DB's terugdraaien methode:

db.rollback (); assertEquals (2, set.size ());

2.4. Serializers

MapDB biedt een grote verscheidenheid aan serializers, die de gegevens binnen de collectie afhandelen. De belangrijkste constructieparameter is de naam, die de individuele collectie binnen de DB voorwerp:

HTreeMap map = db.hashMap ("identificatie_naam") .keySerializer (Serializer.STRING) .valueSerializer (Serializer.LONG) .create ();

Serialisatie wordt aanbevolen, maar is optioneel en kan worden overgeslagen. Het is echter vermeldenswaard dat dit zal leiden tot een langzamer generiek serialisatieproces.

3. HTreeMap

MapDB's HTreeMap biedt Hash kaart en HashSet collecties voor het werken met onze database. HTreeMap is een gesegmenteerde hash-structuur en maakt geen gebruik van een hashtabel met een vaste grootte. In plaats daarvan gebruikt het een automatisch uitbreidende indexboom en worden niet alle gegevens opnieuw verzameld naarmate de tabel groeit. Om het af te maken, HTreeMap is thread-safe en ondersteunt parallel schrijven met behulp van meerdere segmenten.

Laten we om te beginnen een eenvoudig instantiëren Hash kaart dat gebruikt Draad voor zowel sleutels als waarden:

DB db = DBMaker.memoryDB (). Make (); HTreeMap hTreeMap = db .hashMap ("myTreeMap") .keySerializer (Serializer.STRING) .valueSerializer (Serializer.STRING) .create ();

Hierboven hebben we apart gedefinieerd serialisatoren voor de sleutel en de waarde. Nu dat onze Hash kaart is gemaakt, laten we gegevens toevoegen met de leggen methode:

hTreeMap.put ("key1", "value1"); hTreeMap.put ("key2", "value2"); assertEquals (2, hTreeMap.size ());

Net zo Hash kaart werkt op een De hashCode van het object methode, zorgt het toevoegen van gegevens met dezelfde sleutel ervoor dat de waarde wordt overschreven:

hTreeMap.put ("key1", "value3"); assertEquals (2, hTreeMap.size ()); assertEquals ("waarde3", hTreeMap.get ("key1"));

4. SortedTableMap

MapDB's SortedTableMap slaat sleutels op in een tabel met een vaste grootte en gebruikt binair zoeken voor ophalen. Het is vermeldenswaard dat de kaart, eenmaal voorbereid, alleen-lezen is.

Laten we eens kijken hoe u een SortedTableMap. We beginnen met het maken van een geheugen toegewezen volume om de gegevens vast te houden, evenals een sink om gegevens toe te voegen. Bij de eerste aanroep van ons volume stellen we de vlag voor alleen-lezen in op false, zodat we naar het volume kunnen schrijven:

String VOLUME_LOCATION = "gesorteerdTableMapVol.db"; Volume vol = MappedFileVol.FACTORY.makeVolume (VOLUME_LOCATION, false); SortedTableMap.Sink sink = SortedTableMap.create (vol, Serializer.INTEGER, Serializer.STRING) .createFromSink ();

Vervolgens voegen we onze gegevens toe en bellen we het creëren methode op de gootsteen om onze kaart te maken:

for (int i = 0; i <100; i ++) {sink.put (i, "Value" + Integer.toString (i)); } sink.create ();

Nu onze kaart bestaat, kunnen we een alleen-lezen volume definiëren en onze kaart openen met SortedTableMap is geopend methode:

Volume openVol = MappedFileVol.FACTORY.makeVolume (VOLUME_LOCATION, true); SortedTableMap gesorteerdTableMap = SortedTableMap .open (openVol, Serializer.INTEGER, Serializer.STRING); assertEquals (100, gesorteerdTableMap.size ());

4.1. Binaire zoekopdracht

Laten we, voordat we verder gaan, begrijpen hoe de SortedTableMap gebruikt binair zoeken in meer detail.

SortedTableMap splitst de opslag in pagina's, waarbij elke pagina verschillende knooppunten bevat die bestaan ​​uit sleutels en waarden. Binnen deze knooppunten bevinden zich de sleutel-waardeparen die we definiëren in onze Java-code.

SortedTableMap voert drie binaire zoekopdrachten uit om de juiste waarde op te halen:

  1. Sleutels voor elke pagina worden on-heap opgeslagen in een array. De SortedTableMap voert een binaire zoekopdracht uit om de juiste pagina te vinden.
  2. Vervolgens vindt decompressie plaats voor elke sleutel in het knooppunt. Een binaire zoekopdracht stelt het juiste knooppunt vast volgens de sleutels.
  3. eindelijk, de SortedTableMap doorzoekt de sleutels binnen het knooppunt om de juiste waarde te vinden.

5. In-geheugenmodus

MapDB biedt drie soorten opslag in het geheugen. Laten we elke modus snel bekijken, begrijpen hoe deze werkt en de voordelen ervan bestuderen.

5.1. On-Heap

De on-heap-modus slaat objecten op in een eenvoudige Java-collectie Kaart. Het maakt geen gebruik van serialisatie en kan erg snel zijn voor kleine datasets.

Omdat de gegevens echter on-heap worden opgeslagen, wordt de gegevensset beheerd door garbage collection (GC). De duur van GC stijgt met de grootte van de dataset, wat resulteert in prestatieverlies.

Laten we een voorbeeld bekijken waarin de on-heap-modus wordt gespecificeerd:

DB db = DBMaker.heapDB (). Make ();

5.2. Byte[]

Het tweede opslagtype is gebaseerd op byte-arrays. In deze modus gegevens worden geserialiseerd en opgeslagen in arrays tot 1 MB groot. Hoewel technisch gezien on-heap, is deze methode efficiënter voor garbagecollection.

Dit wordt standaard aanbevolen en werd gebruikt in onze ‘Hallo Baeldung ' voorbeeld:

DB db = DBMaker.memoryDB (). Make ();

5.3. DirectByteBuffer

De uiteindelijke winkel is gebaseerd op DirectByteBuffer. Direct geheugen, geïntroduceerd in Java 1.4, maakt het mogelijk gegevens rechtstreeks door te geven aan het native geheugen in plaats van de Java-heap. Als gevolg hiervan worden de gegevens opgeslagen volledig off-heap.

We kunnen een winkel van dit type aanroepen met:

DB db = DBMaker.memoryDirectDB (). Make ();

6. Waarom MapDB?

Dus waarom zou u MapDB gebruiken?

6.1. MapDB versus traditionele database

MapDB biedt een breed scala aan databasefunctionaliteit die is geconfigureerd met slechts een paar regels Java-code. Wanneer we MapDB gebruiken, kunnen we de vaak tijdrovende installatie van verschillende services en verbindingen die nodig zijn om ons programma te laten werken, vermijden.

Daarnaast stelt MapDB ons in staat om toegang te krijgen tot de complexiteit van een database met de vertrouwdheid van een Java-collectie. Met MapDB hebben we geen SQL nodig en kunnen we eenvoudig toegang krijgen tot records krijgen methode aanroepen.

6.2. MapDB versus eenvoudige Java-verzamelingen

Java Collections zal de gegevens van onze applicatie niet bewaren zodra deze stopt met uitvoeren. MapDB biedt een eenvoudige, flexibele, pluggable service waarmee we snel en gemakkelijk de gegevens in onze applicatie kunnen bewaren met behoud van het nut van Java-verzamelingstypen.

7. Conclusie

In dit artikel hebben we dieper ingegaan op de ingebouwde database-engine en het verzamelframework van MapDB.

We zijn begonnen door naar de kernklassen te kijken DB en DBMaker om onze database te configureren, openen en beheren. Vervolgens hebben we enkele voorbeelden doorgenomen van datastructuren die MapDB aanbiedt om met onze records te werken. Ten slotte hebben we gekeken naar de voordelen van MapDB ten opzichte van een traditionele database of Java-collectie.

Zoals altijd is de voorbeeldcode beschikbaar op GitHub.