HarmonyOS分布式数据服务

2024-03-29 15:08

本文主要是介绍HarmonyOS分布式数据服务,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

HarmonyOS分布式数据服务的了解和使用

    • 前言
    • 分布式数据库的版本
      • 单版本分布式数据库
      • 设备协同分布式数据库
    • 约束与限制
    • 相关API接口
      • 首先是对应分布式数据库创建、打开、关闭和删除的接口
      • 然后是对应分布式数据增删改查的接口
      • 谓词查询的接口
      • 订阅分布式数据变化
      • 分布式数据同步
    • 分布式数据库的使用
      • 添加权限并初始化
      • 初始化分布式数据库
      • 分布式数据库的增删改查
      • 分布式数据库观察者
      • 手动同步分布式数据库
      • 分布式数据库谓词查询

前言

已经很久没写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"
}]

然后在MainAbility中初始化:

public class MainAbility extends Ability {@Overridepublic void onStart(Intent intent) {super.onStart(intent);super.setMainRoute(MainAbilitySlice.class.getName());//初始化分布式数据同步权限requestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC"},0);}
}

初始化分布式数据库

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

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

private KvManagerConfig kvManagerConfig;
kvManagerConfig = new KvManagerConfig(this);

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

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

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

private String dbStoreId = "testStoreDemo";
private KvStore kvStore;
Options options = new Options();
kvStore = kvManager.getKvStore(options, dbStoreId);

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

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

public class Options {public Options() {throw new RuntimeException("Stub!");}//检查数据库不存在时是否创建。 默认是falsepublic boolean isCreateIfMissing() {throw new RuntimeException("Stub!");}//setCreateIfMissing(boolean isCreateIfMissing) 默认是truepublic 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!");}//是否设置自动同步  truepublic 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!");}
}

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

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

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

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

分布式数据库的增删改查

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

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

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

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

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

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

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

singleKvStore.delete("stringKey");

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

kvManager.closeKvStore(singleKvStore);

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

kvManager.deleteKvStore(dbStoreId);

以上就是单版本分布式数据库中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;@Overridepublic 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);//initkvManagerConfig = 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);}@Overridepublic void onActive() {super.onActive();}@Overridepublic void onForeground(Intent intent) {super.onForeground(intent);}@Overridepublic 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;}}
}

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 {@Overridepublic void onStart(Intent intent) {super.onStart(intent);super.setMainRoute(MainAbilitySlice.class.getName());requestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC"},0);}
}

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

分布式数据库观察者

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

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

private class kvStoreObserverListener implements KvStoreObserver{@Overridepublic void onChange(ChangeNotification changeNotification) {//todo}
}

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

//新增的数据
List<Entry> insertEntries = changeNotification.getInsertEntries();
//发生改变的数据
List<Entry> updateEntries = changeNotification.getUpdateEntries();
//删除的数据
List<Entry> deleteEntries = changeNotification.getDeleteEntries();
//发生变化的设备id
String deviceId = changeNotification.getDeviceId();

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

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

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"
}]

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

在options中将自动同步关闭:

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

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

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

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

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

将数据进行同步:

singleKvStore.sync(deviceIdList,SyncMode.PUSH_PULL);

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);

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

先要创建一个Schema实例:

Schema schema = new Schema();

然后构建索引集合:

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

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

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

schema.setIndexes(indexList);

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

schema.getRootFieldNode()

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

schema.getRootFieldNode().appendChild(fdName);
schema.getRootFieldNode().appendChild(fdAge);
schema.getRootFieldNode().appendChild(fdSex);

4.设置schema模式

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

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);

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\":\"男\"}");

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

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

Query select = Query.select();

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

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

通过kvstore获取结果集:

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

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

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

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

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;@Overridepublic 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 kvStoreObserverkvStoreObserverListener kvStoreObserverListener = new kvStoreObserverListener();singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL,kvStoreObserverListener);//schema}@Overridepublic void onActive() {super.onActive();}@Overridepublic void onForeground(Intent intent) {super.onForeground(intent);}@Overridepublic 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();//获取设备iddeviceIdList.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{@Overridepublic void onChange(ChangeNotification changeNotification) {System.out.println("发生变化,onChange被回调");//新增的数据List<Entry> insertEntries = changeNotification.getInsertEntries();//发生改变的数据List<Entry> updateEntries = changeNotification.getUpdateEntries();//删除的数据List<Entry> deleteEntries = changeNotification.getDeleteEntries();//发生变化的设备idString deviceId = changeNotification.getDeviceId();}}
}

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

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

这篇关于HarmonyOS分布式数据服务的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/858909

相关文章

Eureka高可用注册中心registered-replicas没有分布式注册中心

自己在学习过程中发现,如果Eureka挂掉了,其他的Client就跑不起来了,那既然是商业项目,还是要处理好这个问题,所以决定用《Spring Cloud微服务实战》(PDF版在全栈技术交流群中自行获取)中说的“高可用注册中心”。 一开始我yml的配置是这样的 server:port: 8761eureka:instance:hostname: 127.0.0.1client:fetch-r

[分布式网络通讯框架]----Zookeeper客户端基本操作----ls、get、create、set、delete

Zookeeper数据结构 zk客户端常用命令 进入客户端 在bin目录下输入./zkCli.sh 查看根目录下数据ls / 注意:要查看哪一个节点,必须把路径写全 查看节点数据信息 get /第一行代码数据,没有的话表示没有数据 创建节点create /sl 20 /sl为节点的路径,20为节点的数据 注意,不能跨越创建,也就是说,创建sl2的时候,必须确保sl

HarmonyOS NEXT:华为开启全新操作系统时代

在全球科技浪潮的汹涌澎湃中,华为再次以创新者的姿态,引领了一场关于操作系统的革命。HarmonyOS NEXT,这一由华为倾力打造的分布式操作系统,不仅是对现有技术的一次大胆突破,更是对未来智能生活的一次深邃展望。 HarmonyOS NEXT并非简单的迭代升级,而是在华为多年技术积淀的基础上,对操作系统的一次彻底重构。它采用微内核架构,摒弃了传统的宏内核模式,实现了模块化和组件化的设计理念

大型网站架构演化(二)——应用服务和数据服务分离

随着网站业务的发展,一台服务器逐渐不能满足需求:越来越多的用户访问导致性能越来越差,越来越多的数据导致存储空间不足。这时就需要将应用和数据分离。应用和数据分离后整个网站使用三台服务器:应用服务器、文件服务器和数据库服务器,如图。              这三台服务器对硬件资源的要求各不相同: 应用服务器需要处理大量的业务逻辑,因此需要更快更强大的CPU;

[分布式网络通讯框架]----ZooKeeper下载以及Linux环境下安装与单机模式部署(附带每一步截图)

首先进入apache官网 点击中间的see all Projects->Project List菜单项进入页面 找到zookeeper,进入 在Zookeeper主页的顶部点击菜单Project->Releases,进入Zookeeper发布版本信息页面,如下图: 找到需要下载的版本 进行下载既可,这里我已经下载过3.4.10,所以以下使用3.4.10进行演示其他的步骤。

分布式事务的解决方案(一)

前言应用场景 事务必须满足传统事务的特性,即原子性,一致性,分离性和持久性。但是分布式事务处理过程中, 某些场地比如在电商系统中,当有用户下单后,除了在订单表插入一条记录外,对应商品表的这个商品数量必须减1吧,怎么保证? 在搜索广告系统中,当用户点击某广告后,除了在点击事件表中增加一条记录外, 还得去商家账户表中找到这个商家并扣除广告费吧,怎么保证? 一 本地事务 以用户A

分布式锁实现方案-基于Redis实现的分布式锁

目录 一、基于Lua+看门狗实现 1.1 缓存实体 1.2 延迟队列存储实体 1.3 分布式锁RedisDistributedLockWithDog 1.4 看门狗线程续期 1.5 测试类 1.6 测试结果 1.7 总结 二、RedLock分布式锁 2.1 Redlock分布式锁简介 2.2 RedLock测试例子 2.3 RedLock 加锁核心源码分析 2.4

分布式,容错:10台电脑坏了2台

由10台电脑组成的分布式系统,随机、任意坏了2台,剩下的8台电脑仍然储存着全部信息,可以继续服务。这是怎么做到的? 设N台电脑,坏了H台,要保证上述性质,需要有冗余,总的存储量降低为1/(H+1)。例如: H=1,随机坏1台,总容量变为1/2; H=2,随机坏2台,总容量变为1/3; 特别地,H=0,总容量不变; H=N-1,总容量变为1/N,这时,每台电脑都储存着全部信息,保证任意坏了N-1台

视频讲解|【双层模型】分布式光伏储能系统的优化配置方法

1 主要内容 该讲解视频对应的程序链接为【双层模型】分布式光伏储能系统的优化配置方法,模型参考《分布式光伏储能系统的优化配置方法》,分为上下层求解方式,上层采用粒子群算法确定储能的选址和容量方案,以全年购电成本、网络损耗、光伏运行成本、储能充放电和投资成本为目标;下层采用混合整数规划算法(默认求解器为cplex,也可替换成gurobi),以IEEE33节点配电网为研究对象,通过二阶锥模型求解,以

HarmonyOS SDK助力鸿蒙原生应用“易感知、易理解、易操作”

6月21-23日,华为开发者大会(HDC 2024)盛大开幕。6月23日上午,《HarmonyOS开放能力,使能应用原生易用体验》分论坛成功举办,大会邀请了多位华为技术专家深度解读如何通过根技术、开放能力、场景化控件等亮点能力,基于人的感知及操作习惯进而设计出更简单易用的鸿蒙原生应用体验,并邀请头部优秀应用介绍其开发实践,分享其在体验创新与简易开发中的经验。 原生易用作为六大鸿蒙原生体验之一