第四章:分布式数据库创建

好,咱们进入正题。分布式数据库的创建,说白了就是给跨设备的数据找个「家」。这个家得能自己搬家、自己备份、自己同步——嗯,听起来挺智能的,但配置起来其实有套路。

4.1 创建分布式数据库

在鸿蒙里,分布式数据库不是传统的关系型数据库,而是基于键值对(KV Store)的。我个人习惯用 distributedKVStore 这个 API,它天然支持跨设备同步。

先看一个最基础的创建流程:

// 获取分布式数据库管理器
DistributedKVStoreManager kvManager = 
    DistributedKVStoreManager.getInstance(context);

// 配置数据库参数
KVStoreConfig config = new KVStoreConfig("my_app_db", "user_data");
config.setSecurityLevel(SecurityLevel.S2);  // 安全等级

// 创建数据库(异步)
kvManager.createKVStore(config, new CreateCallback() {
    @Override
    public void onSuccess(DistributedKVStore kvStore) {
        // 数据库创建成功
        Log.i("DB", "分布式数据库创建成功");
    }
    
    @Override
    public void onFailure(int errorCode, String errorMsg) {
        Log.e("DB", "创建失败: " + errorMsg);
    }
});

这里有个坑——SecurityLevel 别乱设。S2 是默认等级,适合大多数场景。我曾经有个项目为了省事设了 S1,结果数据在传输过程中被截获了...嗯,后来老老实实改回 S2。

4.2 配置同步策略

同步策略是分布式数据库的灵魂。你想想看,两个设备同时修改同一条数据,听谁的?

鸿蒙提供了三种同步模式:

同步模式 说明 适用场景
PULL_ONLY 只拉取远端数据 设备只读场景
PUSH_ONLY 只推送本地数据 传感器上报
PUSH_PULL 双向同步 大多数业务场景

我个人建议:除非你有特殊需求,否则用 PUSH_PULL。但要注意冲突处理——鸿蒙默认是「最后写入者胜出」。如果你需要更精细的控制,可以自定义冲突解决器:

KVStoreSyncStrategy strategy = new KVStoreSyncStrategy();
strategy.setSyncMode(SyncMode.PUSH_PULL);
strategy.setConflictResolver(new ConflictResolver() {
    @Override
    public byte[] resolve(byte[] localValue, byte[] remoteValue, 
                          long localTimestamp, long remoteTimestamp) {
        // 自定义规则:取时间戳较新的
        return localTimestamp > remoteTimestamp ? localValue : remoteValue;
    }
});

避坑指南:我曾经在智能家居项目里,两个设备同时修改了灯光的亮度值。因为没配冲突策略,结果灯一会儿亮一会儿暗...后来加了时间戳比较才解决。

4.3 数据表与字段设计

分布式数据库虽然是 KV 结构,但「表」的概念依然存在。每个 DistributedKVStore 可以理解为一个表,而键值对就是行记录。

设计时我建议遵循三个原则:

  • 键要带前缀:比如 user_001device_002,方便按类型查询
  • 值用 JSON:结构化数据用 JSON 序列化,别用纯字符串
  • 字段精简:只存需要同步的字段,本地缓存放本地数据库

举个例子,一个跨设备待办事项的数据结构:

// 键设计
String key = "todo_" + UUID.randomUUID().toString();

// 值设计(JSON格式)
{
    "title": "买牛奶",
    "status": 0,          // 0:未完成 1:已完成
    "createTime": 1700000000,
    "updateTime": 1700000100,
    "deviceId": "phone_01"
}

这里有个细节:deviceId 字段很重要。为什么?因为分布式环境下,你得知道这条数据是从哪个设备来的。我遇到过一个问题:手机和手表同步待办,手表删了一条,手机也删了一条,结果同步后两条都消失了——加上设备 ID 后,就能区分是谁删的。

4.4 实战:创建待办事项数据库

好,咱们把上面讲的串起来,写一个完整的创建流程:

public class TodoDatabaseManager {
    private DistributedKVStore kvStore;
    
    public void init(Context context) {
        DistributedKVStoreManager manager = 
            DistributedKVStoreManager.getInstance(context);
        
        KVStoreConfig config = new KVStoreConfig("todo_db", "todos");
        config.setSecurityLevel(SecurityLevel.S2);
        
        manager.createKVStore(config, new CreateCallback() {
            @Override
            public void onSuccess(DistributedKVStore store) {
                kvStore = store;
                // 配置同步策略
                KVStoreSyncStrategy strategy = new KVStoreSyncStrategy();
                strategy.setSyncMode(SyncMode.PUSH_PULL);
                strategy.setAutoSync(true);  // 自动同步
                kvStore.setSyncStrategy(strategy);
                
                Log.i("DB", "待办数据库创建成功,已开启自动同步");
            }
        });
    }
    
    // 添加待办
    public void addTodo(String title) {
        String key = "todo_" + System.currentTimeMillis();
        String value = String.format(
            "{\"title\":\"%s\",\"status\":0,\"createTime\":%d}",
            title, System.currentTimeMillis()
        );
        kvStore.put(key, value.getBytes());
    }
}
小技巧setAutoSync(true) 开启后,数据变更会自动同步到其他设备。但要注意网络状态——没网时数据会暂存本地,等网络恢复再同步。

4.5 避坑总结

做分布式数据库,我踩过的坑不少。给你列几个重点:

  • 键名冲突:不同模块用相同前缀,数据会乱。建议按模块划分前缀
  • 同步延迟:分布式不是实时的,别指望毫秒级同步。我一般加个 500ms 的缓冲
  • 数据膨胀:KV 数据库没有自动清理机制。记得定期删除过期数据

嗯,创建分布式数据库其实不难。难的是想清楚「哪些数据需要同步」「冲突了怎么办」。我建议你从一个小功能开始,比如跨设备同步一个计数器,跑通了再上复杂业务。

下一章咱们聊聊数据同步的底层原理——为什么有时候同步会失败?怎么监控同步状态?到时候见。