Skip to content

posix_tutorial_cn

guoling edited this page Apr 19, 2024 · 7 revisions

MMKV for POSIX

MMKV 是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强。从 2015 年中至今在微信上使用,其性能和稳定性经过了时间的验证。近期也已移植到 Android / macOS / Windows / POSIX 平台,一并开源。

使用指南

MMKV 的使用非常简单,所有变更立马生效,无需调用 savesync

配置 MMKV 根目录

  • 在 App 启动时初始化 MMKV,设定 MMKV 的根目录,例如在 main() 函数里:

    #include “MMKV.h”
    
    int main() {
        std::string rootDir = getYourAppDocumentDir();
        MMKV::initializeMMKV(rootDir);
        //...
    }

CRUD 操作

  • MMKV 提供一个全局的实例,可以直接使用:

    auto mmkv = MMKV::defaultMMKV();
    
    mmkv->set(true, "bool");
    std::cout << "bool = " << mmkv->getBool("bool") << std::endl;
    
    mmkv->set(1024, "int32");
    std::cout << "int32 = " << mmkv->getInt32("int32") << std::endl;
    
    mmkv->set(numeric_limits<uint32_t>::max(), "uint32");
    std::cout << "uint32 = " << mmkv->getUInt32("uint32") << std::endl;
    
    mmkv->set(numeric_limits<int64_t>::min(), "int64");
    std::cout << "int64 = " << mmkv->getInt64("int64") << std::endl;
    
    mmkv->set(numeric_limits<uint64_t>::max(), "uint64");
    std::cout << "uint64 = " << mmkv->getUInt64("uint64") << std::endl;
    
    mmkv->set(3.14f, "float");
    std::cout << "float = " << mmkv->getFloat("float") << std::endl;
    
    mmkv->set(numeric_limits<double>::max(), "double");
    std::cout << "double = " << mmkv->getDouble("double") << std::endl;
    
    mmkv->set("Hello, MMKV for Windows", "string");
    std::string result;
    if (mmkv->getString("string", result)) {
       std::cout << "string = " << result << std::endl;
    }

    可以看到,MMKV 在使用上还是比较简单的。

  • 删除 & 查询

    auto kv = MMKV::defaultMMKV();
         
    mmkv->removeValueForKey("bool");
    std::cout << "bool = " << mmkv->getBool("bool") << std::endl;
    
    mmkv->removeValuesForKeys({"int32", "int64"});
    std::cout << "allKeys: ";
    for (auto &key : mmkv->allKeys()) {
        std::cout << key << ", ";
    }
    std::cout << std::endl;
          
    bool hasBool = mmkv->containsKey("bool");
  • 如果不同业务需要区别存储,也可以单独创建自己的实例:

    auto mmkv = MMKV::mmkvWithID("MyID");
    mmkv->set(true, "bool");
  • 如果业务需要多进程访问,那么在初始化的时候加上标志位 MMKV.MULTI_PROCESS_MODE

    auto mmkv = MMKV::mmkvWithID("InterProcessKV", MMKV_MULTI_PROCESS);
    mmkv->set(true, "bool");

支持的数据类型

  • 支持以下 C/C++ 语言基础类型:

    • bool、int32、int64、uint32、uint64、float、double
  • 支持以下类和容器:

    • std::string、std::vector<std::string>、mmkv::MMBuffer

日志

  • MMKV 默认将日志打印到 stdout,不便于对线上问题进行定位和解决。你可以在 App 启动时接收转发 MMKV 的日志。实现mmkv::LogHandler()类型的回调函数,添加类似下面的代码:

    void MyLogHandler(MMKVLogLevel level, const char *file, int line, const char *function, const string &message) {
        auto desc = [level] {
            switch (level) {
                case MMKVLogDebug:
                    return "D";
                case MMKVLogInfo:
                    return "I";
                case MMKVLogWarning:
                    return "W";
                case MMKVLogError:
                    return "E";
                default:
                    return "N";
            }
        }();
        printf("[%s] <%s:%d::%s> %s\n", desc, file, line, function, message.c_str());
    }
    int main() {
        std::string rootDir = getYourAppDocumentDir();
        MMKV::initializeMMKV(rootDir, MMKVLogInfo, MyLogHandler);
        //...
    }

    至于使用哪个日志组件,我们推荐使用 xlog,同样也是开源自微信团队。

  • 如果你不希望 MMKV 打印日志,你可以一劳永逸地关掉它(虽然我们强烈不建议你这么做)。
    注意:除非有非常强烈的证据表明MMKV的日志拖慢了App的速度,你不应该关掉日志。没有日志,日后万一用户有问题,将无法跟进。

    int main() {
        std::string rootDir = getYourAppDocumentDir();
        MMKV::initializeMMKV(rootDir, MMKVLogNone);
        //...
    }

备份 & 恢复

  • MMKV 提供了备份和恢复接口,可用于备份数据到其他目录,并稍后恢复原有数据。

    std::string rootDir = "/tmp/mmkv_backup";
    auto ret = MMKV::backupOneToDirectory(mmapID, rootDir);
    // backup one instance
    var ret = MMKV.backupOneToDirectory(mmapID, backupRootDir);
    // backup all instances
    auto count = MMKV::backupAllToDirectory(rootDir);
    
    // restore one instance
    ret = MMKV::restoreOneFromDirectory(mmapID, rootDir);
    // restore all instances
    count = MMKV::restoreAllFromDirectory(rootDir);

自动过期

  • v1.3.0 起你可以升级 MMKV 到 key 自动过期特性。注意这是格式不向下兼容的升级操作。一旦升级到 key 自动过期,旧版 MMKV (<= v1.2.16) 将无法正常读写该文件。

  • 全局过期. 最简单的用法是给整个文件设定统一的过期间隔。

    // expire in a day
    mmkv->enableAutoKeyExpire(24 * 60 * 60);

    或者,你可以选择只升级 MMKV,但不设置全局过期间隔。这种情况下,默认每个 key 不过期。

    // enable auto key expiration without global duration
    mmkv->enableAutoKeyExpire(MMKV::ExpireNever); // MMKV::ExpireNever = 0
  • 单独过期. 你可以给每个 key 设置单独的过期间隔,区分于文件的全局过期间隔。注意,你仍然需要先升级 MMKV 为 key 自动过期

    // enable auto key expiration with an hour duration
    mmkv->enableAutoKeyExpire(60 * 60);
    
    // set a key with the file's global expiration duration, aka 60 * 60
    mmkv->set("some value", "key_1");
    
    // set a special key that expires in two hours
    mmkv->set("some value", "key_2", 2 * 60 * 60);
    
    // set a special key that never expires
    mmkv->set("some value", "key_3", MMKV::ExpireNever);

    或者,你可以选择只升级 MMKV,但不设置全局过期间隔。这种情况下,默认每个 key 不过期。

    // enable auto key expiration without global duration
    mmkv->enableAutoKeyExpire(MMKV::ExpireNever); // MMKV::ExpireNever = 0
    
    // set a key that never expires
    mmkv->set("some value", "key_1");
    
    // set a special key that expires in an hour
    mmkv->set("some value", "key_2", 60 * 60);
  • 过期间隔的单位是秒。你可以使用任意自定义间隔,例如一周是 7 * 24 * 60 * 60

下一步

Clone this wiki locally