RocksDB快速入门 #
一、第一个RocksDB程序 #
1.1 基本框架 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <iostream>
#include <string>
int main() {
rocksdb::DB* db;
rocksdb::Options options;
// 如果数据库不存在则创建
options.create_if_missing = true;
// 打开数据库
rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/rocksdb_test", &db);
if (!status.ok()) {
std::cerr << "Open database failed: " << status.ToString() << std::endl;
return 1;
}
std::cout << "Database opened successfully!" << std::endl;
// 关闭数据库
delete db;
return 0;
}
1.2 编译运行 #
bash
# 编译
g++ -std=c++17 main.cpp \
-I/path/to/rocksdb/include \
-L/path/to/rocksdb/build \
-lrocksdb \
-lpthread -ldl -lm \
-o main
# 运行
./main
1.3 使用CMake #
cmake
cmake_minimum_required(VERSION 3.10)
project(rocksdb_demo)
set(CMAKE_CXX_STANDARD 17)
# 查找RocksDB
find_package(RocksDB REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main RocksDB::rocksdb)
二、基本读写操作 #
2.1 写入数据 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <iostream>
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db);
if (!status.ok()) {
std::cerr << "Open failed: " << status.ToString() << std::endl;
return 1;
}
// 写入单个键值对
rocksdb::WriteOptions write_options;
status = db->Put(write_options, "name", "RocksDB");
if (status.ok()) {
std::cout << "Write successful!" << std::endl;
}
// 写入多个键值对
db->Put(write_options, "age", "10");
db->Put(write_options, "version", "8.0");
db->Put(write_options, "type", "KV Store");
delete db;
return 0;
}
2.2 读取数据 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <iostream>
int main() {
rocksdb::DB* db;
rocksdb::Options options;
rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db);
if (!status.ok()) {
std::cerr << "Open failed: " << status.ToString() << std::endl;
return 1;
}
// 读取单个值
rocksdb::ReadOptions read_options;
std::string value;
status = db->Get(read_options, "name", &value);
if (status.ok()) {
std::cout << "name = " << value << std::endl;
} else if (status.IsNotFound()) {
std::cout << "Key not found!" << std::endl;
} else {
std::cerr << "Read error: " << status.ToString() << std::endl;
}
// 读取多个值
std::vector<std::string> keys = {"name", "age", "version", "type"};
for (const auto& key : keys) {
status = db->Get(read_options, key, &value);
if (status.ok()) {
std::cout << key << " = " << value << std::endl;
}
}
delete db;
return 0;
}
2.3 删除数据 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <iostream>
int main() {
rocksdb::DB* db;
rocksdb::Options options;
rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db);
if (!status.ok()) {
std::cerr << "Open failed: " << status.ToString() << std::endl;
return 1;
}
// 删除单个键
status = db->Delete(rocksdb::WriteOptions(), "age");
if (status.ok()) {
std::cout << "Delete successful!" << std::endl;
}
// 验证删除
std::string value;
status = db->Get(rocksdb::ReadOptions(), "age", &value);
if (status.IsNotFound()) {
std::cout << "Key 'age' has been deleted!" << std::endl;
}
delete db;
return 0;
}
2.4 检查键是否存在 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <iostream>
bool KeyExists(rocksdb::DB* db, const std::string& key) {
std::string value;
rocksdb::Status status = db->Get(rocksdb::ReadOptions(), key, &value);
return status.ok();
}
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::DB::Open(options, "/tmp/testdb", &db);
// 写入数据
db->Put(rocksdb::WriteOptions(), "key1", "value1");
// 检查键是否存在
if (KeyExists(db, "key1")) {
std::cout << "key1 exists" << std::endl;
}
if (!KeyExists(db, "key2")) {
std::cout << "key2 does not exist" << std::endl;
}
delete db;
return 0;
}
三、批量操作 #
3.1 WriteBatch原子写入 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <rocksdb/write_batch.h>
#include <iostream>
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db);
if (!status.ok()) {
std::cerr << "Open failed: " << status.ToString() << std::endl;
return 1;
}
// 创建批量写入
rocksdb::WriteBatch batch;
// 添加多个操作到batch
batch.Put("key1", "value1");
batch.Put("key2", "value2");
batch.Put("key3", "value3");
batch.Delete("key1"); // 删除刚写入的key1
// 原子执行
status = db->Write(rocksdb::WriteOptions(), &batch);
if (status.ok()) {
std::cout << "Batch write successful!" << std::endl;
}
// 验证结果
std::string value;
// key1应该不存在(被删除)
status = db->Get(rocksdb::ReadOptions(), "key1", &value);
std::cout << "key1 exists: " << (status.ok() ? "yes" : "no") << std::endl;
// key2应该存在
status = db->Get(rocksdb::ReadOptions(), "key2", &value);
if (status.ok()) {
std::cout << "key2 = " << value << std::endl;
}
delete db;
return 0;
}
3.2 批量读取 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <iostream>
#include <vector>
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::DB::Open(options, "/tmp/testdb", &db);
// 准备数据
std::vector<std::pair<std::string, std::string>> data = {
{"user:1", "Alice"},
{"user:2", "Bob"},
{"user:3", "Charlie"},
{"user:4", "David"},
{"user:5", "Eve"}
};
// 批量写入
rocksdb::WriteBatch batch;
for (const auto& [key, value] : data) {
batch.Put(key, value);
}
db->Write(rocksdb::WriteOptions(), &batch);
// 批量读取
std::vector<std::string> keys;
std::vector<std::string> values;
std::vector<rocksdb::Status> statuses;
for (const auto& [key, _] : data) {
keys.push_back(key);
values.push_back(""); // 预分配空间
}
std::vector<rocksdb::Slice> key_slices;
for (const auto& key : keys) {
key_slices.push_back(key);
}
statuses = db->MultiGet(rocksdb::ReadOptions(), key_slices, &values);
// 打印结果
for (size_t i = 0; i < keys.size(); i++) {
if (statuses[i].ok()) {
std::cout << keys[i] << " = " << values[i] << std::endl;
} else {
std::cout << keys[i] << " not found" << std::endl;
}
}
delete db;
return 0;
}
四、迭代器使用 #
4.1 基本迭代 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <iostream>
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::DB::Open(options, "/tmp/testdb", &db);
// 写入测试数据
for (int i = 0; i < 10; i++) {
std::string key = "key" + std::to_string(i);
std::string value = "value" + std::to_string(i);
db->Put(rocksdb::WriteOptions(), key, value);
}
// 创建迭代器
rocksdb::Iterator* it = db->NewIterator(rocksdb::ReadOptions());
// 遍历所有数据
std::cout << "All key-value pairs:" << std::endl;
for (it->SeekToFirst(); it->Valid(); it->Next()) {
std::cout << it->key().ToString() << " => "
<< it->value().ToString() << std::endl;
}
// 检查错误
if (!it->status().ok()) {
std::cerr << "Iterator error: " << it->status().ToString() << std::endl;
}
delete it;
delete db;
return 0;
}
4.2 范围查询 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <iostream>
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::DB::Open(options, "/tmp/testdb", &db);
// 写入有序数据
for (int i = 0; i < 100; i++) {
char key[20];
sprintf(key, "key_%03d", i); // key_000, key_001, ..., key_099
db->Put(rocksdb::WriteOptions(), key, std::to_string(i * 10));
}
// 范围查询:key_020 到 key_040
rocksdb::Iterator* it = db->NewIterator(rocksdb::ReadOptions());
std::cout << "Range [key_020, key_040):" << std::endl;
it->Seek("key_020");
while (it->Valid() && it->key().ToString() < "key_040") {
std::cout << it->key().ToString() << " => "
<< it->value().ToString() << std::endl;
it->Next();
}
delete it;
delete db;
return 0;
}
4.3 反向迭代 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <iostream>
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::DB::Open(options, "/tmp/testdb", &db);
// 写入数据
for (int i = 0; i < 5; i++) {
db->Put(rocksdb::WriteOptions(),
"key" + std::to_string(i),
"value" + std::to_string(i));
}
rocksdb::Iterator* it = db->NewIterator(rocksdb::ReadOptions());
// 反向遍历
std::cout << "Reverse order:" << std::endl;
for (it->SeekToLast(); it->Valid(); it->Prev()) {
std::cout << it->key().ToString() << " => "
<< it->value().ToString() << std::endl;
}
// 从特定位置反向遍历
std::cout << "\nReverse from key3:" << std::endl;
it->Seek("key3");
if (it->Valid()) {
for (; it->Valid(); it->Prev()) {
std::cout << it->key().ToString() << " => "
<< it->value().ToString() << std::endl;
}
}
delete it;
delete db;
return 0;
}
五、快照使用 #
5.1 创建和使用快照 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <iostream>
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::DB::Open(options, "/tmp/testdb", &db);
// 写入初始数据
db->Put(rocksdb::WriteOptions(), "key1", "value1_v1");
db->Put(rocksdb::WriteOptions(), "key2", "value2_v1");
// 创建快照
const rocksdb::Snapshot* snapshot = db->GetSnapshot();
// 修改数据
db->Put(rocksdb::WriteOptions(), "key1", "value1_v2");
db->Put(rocksdb::WriteOptions(), "key2", "value2_v2");
db->Put(rocksdb::WriteOptions(), "key3", "value3_v1");
// 读取当前数据
std::string value;
std::cout << "Current data:" << std::endl;
db->Get(rocksdb::ReadOptions(), "key1", &value);
std::cout << "key1 = " << value << std::endl;
db->Get(rocksdb::ReadOptions(), "key2", &value);
std::cout << "key2 = " << value << std::endl;
db->Get(rocksdb::ReadOptions(), "key3", &value);
std::cout << "key3 = " << value << std::endl;
// 通过快照读取历史数据
std::cout << "\nSnapshot data:" << std::endl;
rocksdb::ReadOptions snapshot_options;
snapshot_options.snapshot = snapshot;
db->Get(snapshot_options, "key1", &value);
std::cout << "key1 = " << value << std::endl;
db->Get(snapshot_options, "key2", &value);
std::cout << "key2 = " << value << std::endl;
rocksdb::Status status = db->Get(snapshot_options, "key3", &value);
if (status.IsNotFound()) {
std::cout << "key3 not found (not in snapshot)" << std::endl;
}
// 释放快照
db->ReleaseSnapshot(snapshot);
delete db;
return 0;
}
5.2 快照迭代 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <iostream>
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::DB::Open(options, "/tmp/testdb", &db);
// 写入初始数据
for (int i = 0; i < 5; i++) {
db->Put(rocksdb::WriteOptions(),
"key" + std::to_string(i),
"v1_" + std::to_string(i));
}
// 创建快照
const rocksdb::Snapshot* snapshot = db->GetSnapshot();
// 修改数据
for (int i = 0; i < 5; i++) {
db->Put(rocksdb::WriteOptions(),
"key" + std::to_string(i),
"v2_" + std::to_string(i));
}
db->Put(rocksdb::WriteOptions(), "key5", "v2_5");
// 使用快照迭代
rocksdb::ReadOptions snapshot_options;
snapshot_options.snapshot = snapshot;
std::cout << "Snapshot iteration:" << std::endl;
rocksdb::Iterator* it = db->NewIterator(snapshot_options);
for (it->SeekToFirst(); it->Valid(); it->Next()) {
std::cout << it->key().ToString() << " => "
<< it->value().ToString() << std::endl;
}
delete it;
// 当前数据迭代
std::cout << "\nCurrent iteration:" << std::endl;
it = db->NewIterator(rocksdb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
std::cout << it->key().ToString() << " => "
<< it->value().ToString() << std::endl;
}
delete it;
db->ReleaseSnapshot(snapshot);
delete db;
return 0;
}
六、简单封装类 #
6.1 RocksDBWrapper #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <memory>
#include <string>
#include <vector>
#include <functional>
class RocksDBWrapper {
public:
RocksDBWrapper(const std::string& db_path) : db_path_(db_path) {
rocksdb::Options options;
options.create_if_missing = true;
options.compression = rocksdb::CompressionType::kLZ4Compression;
rocksdb::Status status = rocksdb::DB::Open(options, db_path, &db_);
if (!status.ok()) {
throw std::runtime_error("Failed to open database: " + status.ToString());
}
}
~RocksDBWrapper() {
if (db_) {
delete db_;
}
}
bool Put(const std::string& key, const std::string& value) {
rocksdb::Status status = db_->Put(rocksdb::WriteOptions(), key, value);
return status.ok();
}
bool Get(const std::string& key, std::string* value) {
rocksdb::Status status = db_->Get(rocksdb::ReadOptions(), key, value);
return status.ok();
}
bool Delete(const std::string& key) {
rocksdb::Status status = db_->Delete(rocksdb::WriteOptions(), key);
return status.ok();
}
bool Exists(const std::string& key) {
std::string value;
return Get(key, &value);
}
void Iterate(std::function<void(const std::string&, const std::string&)> callback) {
rocksdb::Iterator* it = db_->NewIterator(rocksdb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
callback(it->key().ToString(), it->value().ToString());
}
delete it;
}
void IterateRange(const std::string& start, const std::string& end,
std::function<void(const std::string&, const std::string&)> callback) {
rocksdb::Iterator* it = db_->NewIterator(rocksdb::ReadOptions());
it->Seek(start);
while (it->Valid() && it->key().ToString() < end) {
callback(it->key().ToString(), it->value().ToString());
it->Next();
}
delete it;
}
bool WriteBatch(const std::vector<std::pair<std::string, std::string>>& data) {
rocksdb::WriteBatch batch;
for (const auto& [key, value] : data) {
batch.Put(key, value);
}
rocksdb::Status status = db_->Write(rocksdb::WriteOptions(), &batch);
return status.ok();
}
void Flush() {
rocksdb::FlushOptions options;
options.wait = true;
db_->Flush(options);
}
void Compact() {
db_->CompactRange(rocksdb::CompactRangeOptions(), nullptr, nullptr);
}
private:
std::string db_path_;
rocksdb::DB* db_;
};
// 使用示例
int main() {
try {
RocksDBWrapper db("/tmp/mydb");
// 写入数据
db.Put("name", "RocksDB");
db.Put("version", "8.0");
// 读取数据
std::string value;
if (db.Get("name", &value)) {
std::cout << "name = " << value << std::endl;
}
// 批量写入
std::vector<std::pair<std::string, std::string>> data = {
{"key1", "value1"},
{"key2", "value2"},
{"key3", "value3"}
};
db.WriteBatch(data);
// 遍历所有数据
std::cout << "\nAll data:" << std::endl;
db.Iterate([](const std::string& key, const std::string& value) {
std::cout << key << " => " << value << std::endl;
});
// 范围查询
std::cout << "\nRange [key1, key3):" << std::endl;
db.IterateRange("key1", "key3", [](const std::string& key, const std::string& value) {
std::cout << key << " => " << value << std::endl;
});
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
七、错误处理 #
7.1 Status检查 #
cpp
#include <rocksdb/db.h>
#include <rocksdb/options.h>
#include <iostream>
void HandleStatus(const rocksdb::Status& status, const std::string& operation) {
if (status.ok()) {
std::cout << operation << " succeeded" << std::endl;
} else if (status.IsNotFound()) {
std::cout << operation << " - Key not found" << std::endl;
} else if (status.IsCorruption()) {
std::cerr << operation << " - Data corruption: " << status.ToString() << std::endl;
} else if (status.IsIOError()) {
std::cerr << operation << " - IO error: " << status.ToString() << std::endl;
} else if (status.IsInvalidArgument()) {
std::cerr << operation << " - Invalid argument: " << status.ToString() << std::endl;
} else {
std::cerr << operation << " - Error: " << status.ToString() << std::endl;
}
}
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db);
HandleStatus(status, "Open database");
if (!status.ok()) {
return 1;
}
// 写入
status = db->Put(rocksdb::WriteOptions(), "key1", "value1");
HandleStatus(status, "Put key1");
// 读取存在的键
std::string value;
status = db->Get(rocksdb::ReadOptions(), "key1", &value);
HandleStatus(status, "Get key1");
if (status.ok()) {
std::cout << "Value: " << value << std::endl;
}
// 读取不存在的键
status = db->Get(rocksdb::ReadOptions(), "nonexistent", &value);
HandleStatus(status, "Get nonexistent");
delete db;
return 0;
}
八、总结 #
8.1 基本操作速查 #
| 操作 | 方法 | 说明 |
|---|---|---|
| 写入 | db->Put(WriteOptions(), key, value) |
写入单个键值 |
| 读取 | db->Get(ReadOptions(), key, &value) |
读取单个值 |
| 删除 | db->Delete(WriteOptions(), key) |
删除键 |
| 批量写入 | db->Write(WriteOptions(), &batch) |
原子批量操作 |
| 批量读取 | db->MultiGet(ReadOptions(), keys, &values) |
批量读取 |
| 迭代 | db->NewIterator(ReadOptions()) |
创建迭代器 |
| 快照 | db->GetSnapshot() |
创建快照 |
8.2 最佳实践 #
- 使用批量操作:减少IO次数
- 合理使用快照:实现一致性读
- 及时释放资源:删除迭代器和快照
- 检查Status:处理所有可能的错误
下一步,让我们深入学习数据操作!
最后更新:2026-03-27