Panduan untuk MapDB

1. Pengenalan

Dalam artikel ini, kita akan melihat perpustakaan MapDB - enjin pangkalan data tertanam yang diakses melalui API seperti koleksi.

Kami memulakan dengan meneroka kelas teras DB dan DBMaker yang membantu mengkonfigurasi, membuka, dan menguruskan pangkalan data kami. Kemudian, kita akan menyelami beberapa contoh struktur data MapDB yang menyimpan dan mengambil data.

Akhirnya, kita akan melihat beberapa mod dalam memori sebelum membandingkan MapDB dengan pangkalan data tradisional dan Koleksi Java.

2. Menyimpan Data dalam MapDB

Pertama, mari kita memperkenalkan dua kelas yang akan kita gunakan secara berterusan sepanjang tutorial ini - DB dan DBMaker. The DB kelas mewakili pangkalan data terbuka. Kaedahnya memanggil tindakan untuk membuat dan menutup koleksi penyimpanan untuk menangani rekod pangkalan data, serta menangani peristiwa transaksi.

DBMaker menangani konfigurasi, pembuatan, dan pembukaan pangkalan data. Sebagai sebahagian daripada konfigurasi, kita dapat memilih untuk menjadi tuan rumah pangkalan data kita sama ada dalam memori atau sistem fail kita.

2.1. A Simple HashMap Contoh

Untuk memahami bagaimana ini berfungsi, mari kita buat pangkalan data baru dalam memori.

Pertama, mari buat pangkalan data dalam memori baru menggunakan kelas DBMaker :

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

Setelah objek DB kami aktif dan aktif, kita dapat menggunakannya untuk membina HTreeMap untuk bekerja dengan rekod pangkalan data kami:

String welcomeMessageKey = "Welcome Message"; String welcomeMessageString = "Hello Baeldung!"; HTreeMap myMap = db.hashMap("myMap").createOrOpen(); myMap.put(welcomeMessageKey, welcomeMessageString);

HTreeMap adalah pelaksanaan HashMap MapDB . Jadi, setelah kita mempunyai data dalam pangkalan data, kita dapat mengambilnya menggunakan kaedah get :

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

Akhirnya, setelah kita selesai menggunakan pangkalan data, kita harus menutupnya untuk mengelakkan mutasi lebih lanjut:

db.close();

Untuk menyimpan data kami dalam fail, dan bukannya dalam memori, yang perlu kita lakukan adalah mengubah cara objek DB kami dibuat:

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

Contoh kami di atas tidak menggunakan parameter jenis. Hasilnya, kami terus berusaha memberikan hasil agar dapat bekerja dengan jenis tertentu. Dalam contoh seterusnya, kami akan memperkenalkan Serializers untuk menghilangkan keperluan untuk casting.

2.2. Koleksi

MapDB merangkumi pelbagai jenis koleksi. Untuk menunjukkan, mari kita tambahkan dan dapatkan beberapa data dari pangkalan data kami menggunakan NavigableSet , yang berfungsi seperti yang anda harapkan dari Set Java :

Mari mulakan dengan contoh ringkas objek DB kami :

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

Seterusnya, mari buat NavigableSet kami :

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

Di sini, serializer memastikan bahawa data input dari pangkalan data kami bersiri dan deserialized menggunakan objek String .

Seterusnya, mari kita tambahkan beberapa data:

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

Sekarang, mari kita periksa bahawa dua nilai berbeza kita telah ditambahkan ke pangkalan data dengan betul:

assertEquals(2, set.size());

Akhirnya, kerana ini adalah satu set, mari tambahkan rentetan pendua dan sahkan bahawa pangkalan data kami masih mengandungi dua nilai sahaja:

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

2.3. Urus Niaga

Sama seperti pangkalan data tradisional, kelas DB menyediakan kaedah untuk melakukan dan memutar balik data yang kami tambahkan ke pangkalan data kami.

Untuk mengaktifkan fungsi ini, kita perlu menginisialisasi DB kita dengan kaedah transaksi Enable:

DB db = DBMaker.memoryDB().transactionEnable().make();

Seterusnya, mari buat satu set ringkas, tambahkan beberapa data, dan ikuti ke pangkalan data:

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

Sekarang, mari tambahkan rentetan ketiga yang tidak disertakan ke pangkalan data kami:

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

Sekiranya kami tidak berpuas hati dengan data kami, kami dapat mengembalikan data menggunakan kaedah rollback DB :

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

2.4. Serializers

MapDB menawarkan pelbagai jenis serializer, yang menangani data dalam koleksi. Parameter pembinaan yang paling penting adalah nama, yang mengenal pasti koleksi individu dalam objek DB :

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

Walaupun penggambaran disarankan, ia adalah pilihan dan boleh dilangkau. Walau bagaimanapun, perlu diperhatikan bahawa ini akan membawa kepada proses serialisasi generik yang lebih perlahan.

3. HTreeMap

MapDB's HTreeMap provides HashMap and HashSet collections for working with our database. HTreeMap is a segmented hash tree and does not use a fixed-size hash table. Instead, it uses an auto-expanding index tree and does not rehash all of its data as the table grows. To top it off, HTreeMap is thread-safe and supports parallel writes using multiple segments.

To begin, let's instantiate a simple HashMap that uses String for both keys and values:

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

Above, we've defined separate serializers for the key and the value. Now that our HashMap is created, let's add data using the put method:

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

As HashMap works on an Object's hashCode method, adding data using the same key causes the value to be overwritten:

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

4. SortedTableMap

MapDB's SortedTableMap stores keys in a fixed-size table and uses binary search for retrieval. It's worth noting that once prepared, the map is read-only.

Let's walk through the process of creating and querying a SortedTableMap. We'll start by creating a memory-mapped volume to hold the data, as well as a sink to add data. On the first invocation of our volume, we'll set the read-only flag to false, ensuring we can write to the volume:

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

Next, we'll add our data and call the create method on the sink to create our map:

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

Now that our map exists, we can define a read-only volume and open our map using SortedTableMap's open method:

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

4.1. Binary Search

Before we move on, let's understand how the SortedTableMap utilizes binary search in more detail.

SortedTableMap splits the storage into pages, with each page containing several nodes comprised of keys and values. Within these nodes are the key-value pairs that we define in our Java code.

SortedTableMap performs three binary searches to retrieve the correct value:

  1. Keys for each page are stored on-heap in an array. The SortedTableMap performs a binary search to find the correct page.
  2. Next, decompression occurs for each key in the node. A binary search establishes the correct node, according to the keys.
  3. Finally, the SortedTableMap searches over the keys within the node to find the correct value.

5. In-Memory Mode

MapDB offers three types of in-memory store. Let's take a quick look at each mode, understand how it works, and study its benefits.

5.1. On-Heap

The on-heap mode stores objects in a simple Java Collection Map. It does not employ serialization and can be very fast for small datasets.

However, since the data is stored on-heap, the dataset is managed by garbage collection (GC). The duration of GC rises with the size of the dataset, resulting in performance drops.

Let's see an example specifying the on-heap mode:

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

5.2. Byte[]

The second store type is based on byte arrays. In this mode, data is serialized and stored into arrays up to 1MB in size. While technically on-heap, this method is more efficient for garbage collection.

This is recommended by default, and was used in our ‘Hello Baeldung' example:

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

5.3. DirectByteBuffer

The final store is based on DirectByteBuffer. Direct memory, introduced in Java 1.4, allows the passing of data directly to native memory rather than Java heap. As a result, the data will be stored completely off-heap.

We can invoke a store of this type with:

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

6. Why MapDB?

So, why use MapDB?

6.1. MapDB vs Traditional Database

MapDB offers a large array of database functionality configured with just a few lines of Java code. When we employ MapDB, we can avoid the often time-consuming setup of various services and connections needed to get our program to work.

Beyond this, MapDB allows us to access the complexity of a database with the familiarity of a Java Collection. With MapDB, we do not need SQL, and we can access records with simple get method calls.

6.2. Koleksi MapDB vs Simple Java

Java Collections tidak akan meneruskan data aplikasi kami setelah berhenti dijalankan. MapDB menawarkan perkhidmatan yang mudah, fleksibel dan mudah dipasang yang memungkinkan kami menyimpan data dalam aplikasi dengan cepat dan mudah sambil mengekalkan kegunaan jenis pengumpulan Java.

7. Kesimpulannya

Dalam artikel ini, kami telah menyelidiki kerangka enjin pangkalan data dan kerangka pengumpulan MapDB.

Kami memulakan dengan melihat kelas teras DB dan DBMaker untuk mengkonfigurasi, membuka dan menguruskan pangkalan data kami. Kemudian, kami melalui beberapa contoh struktur data yang ditawarkan oleh MapDB untuk berfungsi dengan rekod kami. Akhirnya, kami melihat kelebihan MapDB berbanding pangkalan data tradisional atau Java Collection.

Seperti biasa, kod contoh boleh didapati di GitHub.