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 最佳实践 #

  1. 使用批量操作:减少IO次数
  2. 合理使用快照:实现一致性读
  3. 及时释放资源:删除迭代器和快照
  4. 检查Status:处理所有可能的错误

下一步,让我们深入学习数据操作!

最后更新:2026-03-27