Tutorial: Your First Key-Value Store¶
In this tutorial, you will learn how to initialize an LMDB environment,
write a key-value pair to the database, and read it back using the
lmdbxx C++20 module.
By the end of this guide, you will have a working executable that persists data to your disk.
Prerequisites¶
Before you begin, ensure you have:
A C++20 capable compiler.
The
lmdbxxmodule and the underlying Clmdblibrary linked to your project.A temporary directory on your system to store the database files (we will use
./testdb).
Step 1: Import the Modules¶
Create a new file named main.cpp. Start by importing the standard
library and the lmdbxx module.
import std;
import lmdbxx;
Step 2: Initialize the Environment¶
LMDB uses an “environment” to manage memory mapping and file locks. We must create it, configure it, and open it targeting a directory on our disk.
int main() {
// Create the directory for our database
std::filesystem::create_directory("./testdb");
// Create the LMDB environment wrapper
auto env = lmdbxx::env::create();
// Configure the environment to allow at least one named database
env.set_max_dbs(1);
// Open the environment in our target directory
env.open("./testdb");
// ... we will add more code here
}
Step 3: Write Data (Write Transaction)¶
All read and write operations in LMDB happen inside a transaction. Let’s start a write transaction, open the default database, and store a message.
Add the following to your main function:
// 1. Begin a read-write transaction
auto write_txn = lmdbxx::txn::begin(env);
// 2. Open the main database handle using this transaction
auto db = lmdbxx::dbi::open(write_txn);
// 3. Define our key and value strings
std::string_view key = "greeting";
std::string_view value = "Hello, LMDB C++20 Module!";
// 4. Put the data into the database
db.put(write_txn, key, value);
// 5. Commit the transaction to disk
write_txn.commit();
std::println("Data written successfully.");
Step 4: Read Data (Read-Only Transaction)¶
Now, let’s verify that our data was saved. We will create a new, read-only transaction. Read-only transactions are extremely fast and do not block writers.
// 1. Begin a read-only transaction
auto read_txn = lmdbxx::txn::begin(env, nullptr, lmdbxx::env_flags::rdonly);
// 2. Prepare a string_view to receive the data
std::string_view retrieved_value;
// 3. Search the database for our key
if (db.get(read_txn, "greeting", retrieved_value)) {
std::println("Retrieved: {}", retrieved_value);
} else {
std::println("Key not found!");
}
// Read transactions should be aborted or let fall out of scope when done
read_txn.abort();
return 0;
}
Complete Source Code¶
Here is the complete code for this tutorial. Because lmdbxx uses
RAII wrappers, the database and environment handles will safely close
themselves automatically when they fall out of scope at the end of
main.
import std;
import lmdbxx;
int main() {
std::filesystem::create_directory("./testdb");
auto env = lmdbxx::env::create();
env.set_max_dbs(1);
env.open("./testdb");
// --- Write Data ---
auto write_txn = lmdbxx::txn::begin(env);
auto db = lmdbxx::dbi::open(write_txn);
db.put(write_txn, "greeting", "Hello, LMDB C++20 Module!");
write_txn.commit();
std::println("Data written successfully.");
// --- Read Data ---
auto read_txn = lmdbxx::txn::begin(env, nullptr, lmdbxx::env_flags::rdonly);
std::string_view retrieved_value;
if (db.get(read_txn, "greeting", retrieved_value)) {
std::println("Retrieved: {}", retrieved_value);
}
return 0;
}