当前位置:   article > 正文

HarmonyOS分布式数据服务_distributed_datasync

distributed_datasync

前言

已经很久没写HarmonyOS的内容了,今天我又回来更新了。。。。

HarmonyOS提供了我们在不同设备之间可以获取相同的数据,称之为分布式数据库,只要是信任的设备就都可以获取到保存在分布式数据库里面的数据。所以一般都是在不同设备之间要获取相同数据的场景下使用该数据库。

在使用HarmonyOS分布式数据服务之前,首先要了解一下分布式服务的一些概念以及API。

分布式数据服务(Distributed Data Service,DDS) 为应用程序提供不同设备间数据库数据分布式的能力。通过调用分布式数据接口,应用程序将数据保存到分布式数据库中。通过结合帐号、应用和数据库三元组,分布式数据服务对属于不同应用的数据进行隔离,保证不同应用之间的数据不能通过分布式数据服务互相访问。在通过可信认证的设备间,分布式数据服务支持应用数据相互同步,为用户提供在多种终端设备上最终一致的数据访问体验。

简单来说就是在使用分布式数据服务之后,保存在分布式服务里面的数据,在可信任的设备之间,这些数据是共享的。

可以通过以下图片来查看具体的操作流程,在设备A对数据库进行增删改,那么设备B会同步这些数据,反之也是一样的。

在这里插入图片描述

分布式数据库的版本

在HarmonyOS系统里面,分布式数据库又被分成了两个版本,可以理解为两个模式;分别是单版本分布式数据库和设备协同分布式数据库;两个数据库分别实现不同操作。

单版本分布式数据库

单版本是指数据在本地保存是以单个KV条目为单位的方式保存,对每个Key最多只保存一个条目项,当数据在本地被用户修改时,不管它是否已经被同步出去,均直接在这个条目上进行修改。同步也以此为基础,按照它在本地被写入或更改的顺序将当前最新一次修改逐条同步至远端设备。

简单来说单版本分布式数据库是通过键值对(Key、Value)的形式保存数据,只能有一个key不能重复,当本地key数据被修改的时候会被直接修改,然后将最新的数据再同步出去。

设备协同分布式数据库

设备协同分布式数据库建立在单版本分布式数据库之上,对应用程序存入的KV数据中的Key前面拼接了本设备的DeviceID标识符,这样能保证每个设备产生的数据严格隔离,底层按照设备的维度管理这些数据,设备协同分布式数据库支持以设备的维度查询分布式数据,但是不支持修改远端设备同步过来的数据。

简单来说就是在单版本分布式数据库的key前面拼接上本设备的设备id,保证每个设备的数据库能够区分,知道是哪个设备添加进去的数据;但是不能修改远端设备同步过来的数据,就是在A设备添加的键值对数据推送到B设备,B设备只能读取该数据,不能对该数据进行修改。

约束与限制

HarmonyOS的分布式数据库有着一定的约束和限制,在使用分布式数据库之前要了解这些约束和现房方便在后面的开发中使用。

  • 应用程序如需使用分布式数据服务完整功能,需要申请ohos.permission.DISTRIBUTED_DATASYNC权限。
  • 分布式数据服务的数据模型仅支持KV数据模型,不支持外键、触发器等关系型数据库中的功能。分布式数据服务支持的KV数据模型规格:
    1. 设备协同数据库,针对每条记录,Key的长度≤896 Byte,Value的长度<4 MB。
    2. 单版本数据库,针对每条记录,Key的长度≤1 KB,Value的度<4 MB。
    3. 每个应用程序最多支持同时打开16个分布式数据库。
  • 分布式数据库与本地数据库的使用场景不同,因此开发者应识别需要在设备间进行同步的数据,并将这些数据保存到分布式数据库中。简单来说就是在业务中将要保存到分布式数据库的数据和要保存到关系型数据库或者其他数据库的数据区分开来,保存到自己对应的数据库当中。
  • 分布式数据服务当前不支持应用程序自定义冲突解决策略。在HarmonyOS内部有默认的冲突解决策略。冲突一般发生在多设备同时修改一个Key的数据时。
  • 分布式数据服务针对每个应用程序当前的流控机制:KvStore的接口1秒最大访问1000次,1分钟最大访问10000次;KvManager的接口1秒最大访问50次,1分钟最大访问500次。

相关API接口

在使用分布式数据库之前还要了解官方给我们提供了哪些api接口,然后根据api接口进行开发。

首先是对应分布式数据库创建、打开、关闭和删除的接口

  • isCreateIfMissing() 检查数据库不存在时是否创建。
  • setCreateIfMissing(boolean isCreateIfMissing) 设置数据库不存在时是否创建。
  • isEncrypt() 获取数据库是否加密。
  • setEncrypt(boolean isEncrypt) 设置数据库是否加密。
  • getStoreType() 获取分布式数据库的类型。
  • setStoreType(KvStoreType storeType) 设置分布式数据库的类型。
  • KvStoreType.DEVICE_COLLABORATION 设备协同分布式数据库类型。
  • KvStoreType.SINGLE_VERSION 单版本分布式数据库类型
  • getKvStore(Options options, String storeId) 根据Options配置创建和打开标识符为storeId的分布式数据库。
  • closeKvStore(KvStore kvStore) 关闭分布式数据库。
  • deleteKvStore(String storeId) 删除分布式数据库。

然后是对应分布式数据增删改查的接口

在对数据库执行增删改查。

  1. 插入和更新数据
    - putBoolean(String key, boolean value) 插入和更新Boolea类型数据
    - putInt(String key, int value) 插入和更新Int类型数据
    - putFloat(String key, float value) 插入和更新Float类型数据
    - putDouble(String key, double value) 插入和更新Double类型数据
    - putString(String key, String value) 插入和更新String类型数据
    - putByteArray(String key, byte[] value) 插入和更新ByteArray类型数据
    - putBatch(List entries) 插入和更新Batch类型数据

  2. 删除数据
    - delete(String key) 删除指定key数据
    - deleteBatch(List keys) 删除指定keys数据

  3. 查询数据
    - getInt(String key) 查询指定key数据
    - getFloat(String key)
    - getDouble(String key)
    - getString(String key)
    - getByteArray(String key)
    - getEntries(String keyPrefix)

谓词查询的接口

对于Schema数据库谓词查询数据,使用Query构建查询条件。

  • select() 查询条件
  • reset()
  • equalTo(String field, int value) 等于 field 字段名 value 值
  • equalTo(String field, long value)
  • equalTo(String field, double value)
  • equalTo(String field, String value)
  • equalTo(String field, boolean value)
  • notEqualTo(String field, int value) 不等于 field 字段名 value 值
  • notEqualTo(String field, long value)
  • notEqualTo(String field, boolean value)
  • notEqualTo(String field, String value)
  • notEqualTo(String field, double value)
  • greaterThan(String field, int value) 大于field 字段名 value 值
  • greaterThan(String field, long value)
  • greaterThan(String field, double value)
  • greaterThan(String field, String value)
  • lessThan(String field, int value) 小于field 字段名 value 值
  • lessThan(String field, long value)
  • lessThan(String field, double value)
  • lessThan(String field, String value)
  • greaterThanOrEqualTo(String field, int value) 大于等于 field 字段名 value 值
  • greaterThanOrEqualTo(String field, long value)
  • greaterThanOrEqualTo(String field, double value)
  • greaterThanOrEqualTo(String field, String value)
  • lessThanOrEqualTo(String field, int value) 小于等于 field 字段名 value 值
  • lessThanOrEqualTo(String field, long value)
  • lessThanOrEqualTo(String field, double value)
  • lessThanOrEqualTo(String field, String value)
  • isNull(String field) 不为空field 字段名
  • orderByDesc(String field) 排序
  • orderByAsc(String field)
  • limit(int number, int offset)
  • like(String field, String value)
  • unlike(String field, String value)
  • inInt(String field, List valueList)
  • inLong(String field, List valueList)
  • inDouble(String field, List valueList)
  • inString(String field, List valueList)
  • notInInt(String field, List valueList)
  • notInLong(String field, List valueList)
  • notInDouble(String field, List valueList)
  • notInString(String field, List valueList)
  • and()
  • or()

订阅分布式数据变化

订阅数据库中数据的变化。

  • subscribe(SubscribeType subscribeType, KvStoreObserver observer)

分布式数据同步

在手动模式下,触发数据库同步。

  • sync(List deviceIdList, SyncMode mode)

分布式数据库的使用

在了解分布式数据库的版本、约束以及相关API接口之后就是对分布式数据库的使用实操了;虽然HarmonyOS将分布式数据库的版本区分成了单版本分布式数据库和设备协同分布式数据库两种,但是用法都是一样的,这里就以单版本分布式数据库来进行操作。

添加权限并初始化

在使用分布式数据库之前要先添加分布式数据同步权限,并且初始化。
首先在module下添加权限:

"reqPermissions": [{
      "name": "ohos.permission.DISTRIBUTED_DATASYNC"
}]
  • 1
  • 2
  • 3

然后在MainAbility中初始化:

public class MainAbility extends Ability {
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setMainRoute(MainAbilitySlice.class.getName());
		//初始化分布式数据同步权限
        requestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC"},0);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

初始化分布式数据库

初始化分布式数据库和初始化关系型数据库差不多,同样是三个步骤先获取KvManagerConfig,然后获取KvManager,最后再获取KvStore就拿到数据库了。

1.获取KvManagerConfig
直接在onStart方法里面进行获取,传入当前abilitySlice的上下文对象:

private KvManagerConfig kvManagerConfig;
kvManagerConfig = new KvManagerConfig(this);
  • 1
  • 2

2.获取KvManager数据库管理器
通过KvManagerFactory去获取数据库管理器,传入上面的数据库配置管理器:

private KvManager kvManager;
kvManager = KvManagerFactory.getInstance().createKvManager(kvManagerConfig);
  • 1
  • 2

3.获取KvStore分布式数据库
通过kvManager的getKvStore方法获取,需要传入Options和一个String类型的数据库标识:

private String dbStoreId = "testStoreDemo";
private KvStore kvStore;
Options options = new Options();
kvStore = kvManager.getKvStore(options, dbStoreId);
  • 1
  • 2
  • 3
  • 4

以上操作都在onStart方法中完成。

Options 参数解析,这里的Options是在ohos.data.distributed.common这个包下面的,里面包含的方法就是上面api上提到的对应分布式数据库创建、打开、关闭和删除的接口:

public class Options {
    public Options() {
        throw new RuntimeException("Stub!");
    }
	//检查数据库不存在时是否创建。 默认是false
    public boolean isCreateIfMissing() {
        throw new RuntimeException("Stub!");
    }
	//setCreateIfMissing(boolean isCreateIfMissing) 默认是true
    public Options setCreateIfMissing(boolean isCreateIfMissing) {
        throw new RuntimeException("Stub!");
    }
	//isEncrypt() 获取数据库是否加密。
    public boolean isEncrypt() {
        throw new RuntimeException("Stub!");
    }
	//设置数据库是否加密。
    public Options setEncrypt(boolean isEncrypt) {
        throw new RuntimeException("Stub!");
    }

    public boolean isBackup() {
        throw new RuntimeException("Stub!");
    }

    public Options setBackup(boolean isBackup) {
        throw new RuntimeException("Stub!");
    }
	
    public boolean isAutoSync() {
        throw new RuntimeException("Stub!");
    }
	//是否设置自动同步  true
    public Options setAutoSync(boolean isAutoSync) {
        throw new RuntimeException("Stub!");
    }
	//数据库类型  默认是设备协同分布式数据库
    public KvStoreType getKvStoreType() {
        throw new RuntimeException("Stub!");
    }

    public Options setKvStoreType(KvStoreType kvStoreType) {
        throw new RuntimeException("Stub!");
    }

    public Schema getSchema() {
        throw new RuntimeException("Stub!");
    }

    public Options setSchema(Schema schema) {
        throw new RuntimeException("Stub!");
    }

    public SecurityLevel getSecurityLevel() {
        throw new RuntimeException("Stub!");
    }

    public Options setSecurityLevel(SecurityLevel securityLevel) {
        throw new RuntimeException("Stub!");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

这里有几个参数需要注意:

  • isCreateIfMissing 没有数据库是否创建,默认是false,所以要设置成true
  • getKvStoreType 数据库类型,默认是设备协同分布式数据库

可以根据自己的需求配置Options。

通过以上步骤就可以将单版本分布式数据库创建并初始化成功了。

分布式数据库的增删改查

对分布式数据库进行增删改查。

前面有介绍到分布式数据库的增删改查API,这里就使用API进行数据库操作就行了,写入用put,读取用get,删除用delete;因为后面都是根据数据类型区分,获取的时候也要通过对应的数据类型去获取,这里就使用string来进行举例。

使用单版本分布式数据库写入String类型的数据:

singleKvStore.putString("stringKey","hello word");
  • 1

读取单版本分布式数据库中String类型的数据:

String stringValue = singleKvStore.getString("stringKey");
  • 1

删除单版本分布式数据库中指定key的数据:

singleKvStore.delete("stringKey");
  • 1

使用数据库管理器kvManager关闭数据库:

kvManager.closeKvStore(singleKvStore);
  • 1

使用数据库管理器kvManager删除数据库:

kvManager.deleteKvStore(dbStoreId);
  • 1

以上就是单版本分布式数据库中string类型数据的一系列操作,如果要写入其他数据类型则使用其他 API就可以实现了;到目前位置MainAbilitySlice的所有代码如下:

package com.example.myapplication.slice;

import com.example.myapplication.ResourceTable;
import ohos.aafwk.ability.AbilityForm;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.ability.OnClickListener;
import ohos.aafwk.ability.ViewsStatus;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.data.distributed.common.*;
import ohos.data.distributed.user.SingleKvStore;

public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener {

    private Text btnEdit,
            btnRead,
            btnDelete,
            btnCloseDB,
            btnDeleteDB;

    private KvManagerConfig kvManagerConfig;
    private KvManager kvManager;
    private String dbStoreId = "testStoreDemo";
    private SingleKvStore singleKvStore;
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);

        btnEdit = (Text) findComponentById(ResourceTable.Id_edit_data);
        btnRead = (Text) findComponentById(ResourceTable.Id_read_data);
        btnDelete = (Text) findComponentById(ResourceTable.Id_delete_data);
        btnCloseDB = (Text) findComponentById(ResourceTable.Id_close_db);
        btnDeleteDB = (Text) findComponentById(ResourceTable.Id_delete_db);

        btnEdit.setClickedListener(this);
        btnRead.setClickedListener(this);
        btnDelete.setClickedListener(this);
        btnCloseDB.setClickedListener(this);
        btnDeleteDB.setClickedListener(this);

        //init
        kvManagerConfig = new KvManagerConfig(this);
        kvManager = KvManagerFactory.getInstance().createKvManager(kvManagerConfig);
        Options options = new Options();
        options.setCreateIfMissing(true);
        options.setEncrypt(false);
        options.setKvStoreType(KvStoreType.SINGLE_VERSION);
        singleKvStore = kvManager.getKvStore(options, dbStoreId);
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }

    @Override
    public void onClick(Component component) {
        switch (component.getId()){
            case ResourceTable.Id_edit_data:
                try {
                    singleKvStore.putString("stringKey","hello word");
                }catch (Exception e){
                    System.out.println("edit error:"+e.getMessage());
                }
                break;
            case ResourceTable.Id_read_data:
                try {
                    String stringValue = singleKvStore.getString("stringKey");
                    System.out.println("read success:" + stringValue);
                }catch (Exception e){
                    System.out.println("read error:"+e.getMessage());
                }
                break;
            case ResourceTable.Id_delete_data:
                try {
                    singleKvStore.delete("stringKey");
                    System.out.println("delete success");
                }catch (Exception e){
                    System.out.println("delete error:"+e.getMessage());
                }
                break;
            case ResourceTable.Id_close_db:
                try {
                    kvManager.closeKvStore(singleKvStore);
                    System.out.println("close db success");
                }catch (Exception e){
                    System.out.println("close db error:"+e.getMessage());
                }
                break;
            case ResourceTable.Id_delete_db:
                try {
                    kvManager.deleteKvStore(dbStoreId);
                    System.out.println("delete db success");
                }catch (Exception e){
                    System.out.println("delete db error:"+e.getMessage());
                }
                break;
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108

MainAbility代码如下:

package com.example.myapplication;

import com.example.myapplication.slice.MainAbilitySlice;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;

public class MainAbility extends Ability {
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setMainRoute(MainAbilitySlice.class.getName());

        requestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC"},0);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

想要测试的话可以将代码跑起来,要跑在两个设备上面,然后测试在一个设备写入,另一个设备读取,一个设备删除,另一个设备读取以及关闭,删除数据库等操作;要在多设备运行才能感受到效果。

分布式数据库观察者

在前面的文档中有说到订阅数据库中数据的变化,通过实现KvStoreObserver接口,构造并注册KvStoreObserver示例,通过onChange方法的回调来监听数据库的变化。

首先创建一个内部类,并且实现KvStoreObserver接口:

private class kvStoreObserverListener implements KvStoreObserver{
    @Override
    public void onChange(ChangeNotification changeNotification) {
    	//todo
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在onChange里面监听数据变化,onChange的参数是传过来一个发生改变的通知,通过该通知可以监听到以下数据:

//新增的数据
List<Entry> insertEntries = changeNotification.getInsertEntries();
//发生改变的数据
List<Entry> updateEntries = changeNotification.getUpdateEntries();
//删除的数据
List<Entry> deleteEntries = changeNotification.getDeleteEntries();
//发生变化的设备id
String deviceId = changeNotification.getDeviceId();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

将该观察者添加到单版本分布式数据库当中去:

kvStoreObserverListener kvStoreObserverListener = new kvStoreObserverListener();
singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL,kvStoreObserverListener);
  • 1
  • 2

subscribe参数解析:

  • SubscribeType 观察者类型
    1. SUBSCRIBE_TYPE_LOCAL 只观察当前设备
    2. SUBSCRIBE_TYPE_REMOTE 只观察远端设备
    3. SUBSCRIBE_TYPE_ALL 当前设备和远端设备同时观察
  • KvStoreObserver 观察者

以上就是分布式数据库观察者的使用。

手动同步分布式数据库

前面在使用单版本分布式数据库的时候,我们使用的options的同步模式是默认的,默认是自动同步;官方也给出了手动同步的方法,通过DeviceManager获取在线设备,然后再同步数据到设备上,这里就进行一下操作。

在使用DeviceManager获取在线设备之前要先在config.json里面添加以下权限:

"reqPermissions": [{
    "name": "ohos.permission.DISTRIBUTED_DATASYNC"
},{
    "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
},{
    "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
},{
    "name": "ohos.permission.GET_BUNDLE_INFO"
}]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

不添加权限会报错,因为没有权限就无法读取到其他在线设备的信息。

在options中将自动同步关闭:

options.setAutoSync(false);//设置自动同步关闭
  • 1

通过DeviceManager获取在线设备列表:

List<DeviceInfo> deviceList = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
  • 1

获取将自身除外的所有已连接的设备id:

//获取已连接的在线的所有设备id(当前设备本身除外)
ArrayList<String> deviceIdList = new ArrayList<>();
//循环遍历  获取除了自己以外其他在线的设备id,并添加到id集合里面去
for (DeviceInfo deviceInfo : deviceList){
      String deviceId = deviceInfo.getDeviceId();//获取设备id
      deviceIdList.add(deviceId);//添加到设备id集合里面去
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

将数据进行同步:

singleKvStore.sync(deviceIdList,SyncMode.PUSH_PULL);
  • 1

sync参数解析:

  • deviceIdList 在线的设备id(集合)
  • SyncMode 同步模式
    1. PUSH_PULL 将远程设备数据拉取到本地,也将本地数据推送到远程设备
    2. PULL_ONLY 远程设备的数据拿到本地
    3. PUSH_ONLY 将本地数据推送到远程设备

这个功能同样要运行到多个设备才能看出来效果。

分布式数据库谓词查询

使用谓词去查询分布式数据库的结果;在使用谓词之前有一个前提条件,那就是必须指定一个Schema。Schema是分布式数据库的一种约束规则。想要使用谓词查询还要给kv的value绑定一个字段,构建出表结构。

比如创建一个学生的key value:
key:student
value:就要包含字段,比如name、age、sex等等。

创建要使用谓词查询的分布式数据库步骤如下:

1.构造谓词查询中使用的字段
这里的字段指的是一种约束,约束kv键值对里面的value,约束该值的数据类型,约束该值是否可以为空,约束该值给它绑定一个字段名字等等。

该字段有了名字,就可以通过该字段的名字进行查询,也就是谓词查询。

比如我们创建一个学生,然后他有年龄,名字,性别三个字段:

FieldNode fdName = new FieldNode("name");//构造一个名字为name的字段
fdName.setType(FieldValueType.STRING);//设置字段数据类型
fdName.setNullable(false);//设置字段不能为空
FieldNode fdAge = new FieldNode("age");//创建一个名字为age的字段
fdAge.setType(FieldValueType.INTEGER);
fdAge.setNullable(false);
FieldNode fdSex = new FieldNode("sex");//创建一个名字为sex的字段
fdSex.setType(FieldValueType.STRING);
fdSex.setNullable(false);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2.将字段信息设置到schema里面去

先要创建一个Schema实例:

Schema schema = new Schema();
  • 1

然后构建索引集合:

ArrayList<String> indexList = new ArrayList<>();//构建索引集合
indexList.add("$.name");//写法规定  通过  $. 跟上字段名
indexList.add("$.age");//写法规定  通过  $. 跟上字段名
  • 1
  • 2
  • 3

给索引集合添加索引的时候写法是固定的,$. 字段名。

最后将索引集合设置到schema里面去:

schema.setIndexes(indexList);
  • 1

3.创建关联,将所有字段和schema关联起来,将字段添加为schema根节点下面的子节点,首先要获取根节点:

schema.getRootFieldNode()
  • 1

将字段添加为根节点下面的子节点:

schema.getRootFieldNode().appendChild(fdName);
schema.getRootFieldNode().appendChild(fdAge);
schema.getRootFieldNode().appendChild(fdSex);
  • 1
  • 2
  • 3

4.设置schema模式

/**
* 4. 设置schema模式
*
* STRICT  严格(schema里面包含的字段在该模式下必须顺手,对kv里面的value约束较大,value必须符合字段约束)
* COMPATIBLE 兼容(schema里面包含的字段约束在该模式下可以遵守也可以不遵守,对kv里面的value约束比较小)
* */
schema.setSchemaMode(SchemaMode.COMPATIBLE);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

5.schema关联数据库

/**
* 5. schema关联数据库
*
* options.setSchema(schema);
* */
kvManagerConfig = new KvManagerConfig(this);
kvManager = KvManagerFactory.getInstance().createKvManager(kvManagerConfig);
Options options = new Options();
options.setCreateIfMissing(true);
options.setEncrypt(false);
options.setKvStoreType(KvStoreType.SINGLE_VERSION);
options.setSchema(schema);
singleKvStore = kvManager.getKvStore(options, dbStoreId);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

6.使用谓词查询后数据库的读写发生了变化,首先是写入,还是kv键值对的方式,但是value变成了一个对象,对象里面包含上面设置的字段名以及字段对应的值

//使用谓词查询插入数据
//key  stringKey_1
//value "{\"name\":\"张三\",\"age\":20,\"sex\":\"男\"}"
singleKvStore.putString("stringKey_1","{\"name\":\"张三\",\"age\":20,\"sex\":\"男\"}");
singleKvStore.putString("stringKey_2","{\"name\":\"李四\",\"age\":20,\"sex\":\"男\"}");
singleKvStore.putString("stringKey_3","{\"name\":\"王五\",\"age\":20,\"sex\":\"男\"}");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

7.使用谓词查询后数据的读取

首先要构建一个查询对象,也就是谓词查询的selet,先获取query实例:

Query select = Query.select();
  • 1

设置查询条件,查询年龄为20的数据:

select.equalTo("$.age", 20);
  • 1

通过kvstore获取结果集:

List<Entry> entries = singleKvStore.getEntries(select);
  • 1

循环打印结果集里面的数据:

for (Entry entry: entries){
     System.out.println("read success:" + entry.getValue().getString());
}
  • 1
  • 2
  • 3

控制台结果如下:
在这里插入图片描述
更多的谓词查询条件这里就不做过多的演示了。

MainAbilitySlice所有代码如下:

package com.example.myapplication.slice;

import com.example.myapplication.ResourceTable;
import ohos.aafwk.ability.AbilityForm;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.ability.OnClickListener;
import ohos.aafwk.ability.ViewsStatus;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.data.distributed.common.*;
import ohos.data.distributed.user.SingleKvStore;
import ohos.distributedschedule.interwork.DeviceInfo;
import ohos.distributedschedule.interwork.DeviceManager;

import java.util.ArrayList;
import java.util.List;

public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener {

    private Text btnEdit,
            btnRead,
            btnDelete,
            btnCloseDB,
            btnDeleteDB,btnSyncDB;

    private KvManagerConfig kvManagerConfig;
    private KvManager kvManager;
    private String dbStoreId = "testStoreDemo";
    private SingleKvStore singleKvStore;
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);

        btnEdit = (Text) findComponentById(ResourceTable.Id_edit_data);
        btnRead = (Text) findComponentById(ResourceTable.Id_read_data);
        btnDelete = (Text) findComponentById(ResourceTable.Id_delete_data);
        btnCloseDB = (Text) findComponentById(ResourceTable.Id_close_db);
        btnDeleteDB = (Text) findComponentById(ResourceTable.Id_delete_db);
        btnSyncDB = (Text) findComponentById(ResourceTable.Id_sync_db);

        btnEdit.setClickedListener(this);
        btnRead.setClickedListener(this);
        btnDelete.setClickedListener(this);
        btnCloseDB.setClickedListener(this);
        btnDeleteDB.setClickedListener(this);
        btnSyncDB.setClickedListener(this);

        //init 不适用谓词查询创建数据库
//        kvManagerConfig = new KvManagerConfig(this);
//        kvManager = KvManagerFactory.getInstance().createKvManager(kvManagerConfig);
//        Options options = new Options();
//        options.setCreateIfMissing(true);
//        options.setEncrypt(false);
//        options.setKvStoreType(KvStoreType.SINGLE_VERSION);
//        options.setAutoSync(false);//设置自动同步关闭
//        singleKvStore = kvManager.getKvStore(options, dbStoreId);

        //init 使用谓词查询创建数据库
        /**
         * 1.构造谓词查询中使用的字段  字段是一系列约束,约束kv键值对里面的value,约束该值的数据类型,约束该值是否可以为空,约束该值给它绑定一个字段名字
         *
         * 该字段有了名字,就可以通过该字段的名字进行查询,也就是谓词查询。
         * */
        FieldNode fdName = new FieldNode("name");//构造一个名字为name的字段
        fdName.setType(FieldValueType.STRING);//设置字段数据类型
        fdName.setNullable(false);//设置字段不能为空
        FieldNode fdAge = new FieldNode("age");//创建一个名字为age的字段
        fdAge.setType(FieldValueType.INTEGER);
        fdAge.setNullable(false);
        FieldNode fdSex = new FieldNode("sex");//创建一个名字为sex的字段
        fdSex.setType(FieldValueType.STRING);
        fdSex.setNullable(false);

        /**
         * 2. 创建schema
         *
         * 将字段信息设置到schema里面去
         * */
        Schema schema = new Schema();
        ArrayList<String> indexList = new ArrayList<>();//构建索引集合
        indexList.add("$.name");//写法规定  通过  $. 跟上字段名
        indexList.add("$.age");//写法规定  通过  $. 跟上字段名
        schema.setIndexes(indexList);

        /**
         * 3. 创建关联
         * schema.getRootFieldNode(); 获取schema的根字段节点
         * 将所有字段和schema对象关联起来,将字段添加为schema根字段节点下面的子节点
         * */
        schema.getRootFieldNode().appendChild(fdName);
        schema.getRootFieldNode().appendChild(fdAge);
        schema.getRootFieldNode().appendChild(fdSex);

        /**
         * 4. 设置schema模式
         *
         * STRICT  严格(schema里面包含的字段在该模式下必须顺手,对kv里面的value约束较大,value必须符合字段约束)
         * COMPATIBLE 兼容(schema里面包含的字段约束在该模式下可以遵守也可以不遵守,对kv里面的value约束比较小)
         * */
        schema.setSchemaMode(SchemaMode.COMPATIBLE);

        /**
         * 5. schema关联数据库
         *
         * options.setSchema(schema);
         * */
        kvManagerConfig = new KvManagerConfig(this);
        kvManager = KvManagerFactory.getInstance().createKvManager(kvManagerConfig);
        Options options = new Options();
        options.setCreateIfMissing(true);
        options.setEncrypt(false);
        options.setKvStoreType(KvStoreType.SINGLE_VERSION);
        options.setSchema(schema);
        singleKvStore = kvManager.getKvStore(options, dbStoreId);

        //bind kvStoreObserver
        kvStoreObserverListener kvStoreObserverListener = new kvStoreObserverListener();
        singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL,kvStoreObserverListener);

        //schema
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }

    @Override
    public void onClick(Component component) {
        switch (component.getId()){
            case ResourceTable.Id_edit_data:
                try {
                    //不使用谓词查询插入数据
//                    singleKvStore.putString("stringKey","hello word");

                    //使用谓词查询插入数据
                    singleKvStore.putString("stringKey_1","{\"name\":\"张三\",\"age\":20,\"sex\":\"男\"}");
                    singleKvStore.putString("stringKey_2","{\"name\":\"李四\",\"age\":20,\"sex\":\"男\"}");
                    singleKvStore.putString("stringKey_3","{\"name\":\"王五\",\"age\":20,\"sex\":\"男\"}");
                }catch (Exception e){
                    System.out.println("edit error:"+e.getMessage());
                }
                break;
            case ResourceTable.Id_read_data:
                try {
                    //不使用谓词读取数据
//                    String stringValue = singleKvStore.getString("stringKey");
//                    System.out.println("read success:" + stringValue);

                    //使用谓词读取数据
                    Query select = Query.select();//获取查询条件
                    select.equalTo("$.age", 20);

                    List<Entry> entries = singleKvStore.getEntries(select);
                    for (Entry entry: entries){
                        System.out.println("read success:" + entry.getValue().getString());
                    }


//                    KvStoreResultSet resultSet = singleKvStore.getResultSet(select);
                }catch (Exception e){
                    System.out.println("read error:"+e.getMessage());
                }
                break;
            case ResourceTable.Id_delete_data:
                try {
                    singleKvStore.delete("stringKey");
                    System.out.println("delete success");
                }catch (Exception e){
                    System.out.println("delete error:"+e.getMessage());
                }
                break;
            case ResourceTable.Id_close_db:
                try {
                    kvManager.closeKvStore(singleKvStore);
                    System.out.println("close db success");
                }catch (Exception e){
                    System.out.println("close db error:"+e.getMessage());
                }
                break;
            case ResourceTable.Id_delete_db:
                try {
                    kvManager.deleteKvStore(dbStoreId);
                    System.out.println("delete db success");
                }catch (Exception e){
                    System.out.println("delete db error:"+e.getMessage());
                }
                break;
            case ResourceTable.Id_sync_db:
                try {
                    //获取在线设备列表
                    List<DeviceInfo> deviceList = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
                    //获取已连接的在线的所有设备id(当前设备本身除外)
                    ArrayList<String> deviceIdList = new ArrayList<>();
                    //循环遍历  获取除了自己以外其他在线的设备id,并添加到id集合里面去
                    for (DeviceInfo deviceInfo : deviceList){
                        String deviceId = deviceInfo.getDeviceId();//获取设备id
                        deviceIdList.add(deviceId);//添加到设备id集合里面去
                    }
                    //PULL_ONLY 远程设备的数据拿到本地
                    //PUSH_ONLY 将本地数据推送到远程设备
                    //PUSH_PULL 将远程设备数据拉取到本地,也将本地数据推送到远程设备
                    singleKvStore.sync(deviceIdList,SyncMode.PUSH_PULL);
                    System.out.println("sync db success");
                }catch (Exception e){
                    System.out.println("sync db error:"+e.getMessage());
                }
                break;
        }
    }

    private class kvStoreObserverListener implements KvStoreObserver{
        @Override
        public void onChange(ChangeNotification changeNotification) {
            System.out.println("发生变化,onChange被回调");
            //新增的数据
            List<Entry> insertEntries = changeNotification.getInsertEntries();
            //发生改变的数据
            List<Entry> updateEntries = changeNotification.getUpdateEntries();
            //删除的数据
            List<Entry> deleteEntries = changeNotification.getDeleteEntries();
            //发生变化的设备id
            String deviceId = changeNotification.getDeviceId();
        }
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235

还是那句话要运行演示记得运行在多设备上,以便更加直观的看出效果。

HarmonyOS分布式数据库服务到这里就简单的学习完了~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/267760
推荐阅读
相关标签
  

闽ICP备14008679号