HarmonyOS NEXT鸿蒙开发:数据持久化-键值数据库

介绍

官网指南

官网API

键值型数据库存储 键值对 形式的数据

应用场景

当需要存储的数据 没有复杂的关系模型,比如:

  • 存储商品名称、对应价格
  • 存储员工工号、今日是否已出勤

约束限制

  • 设备协同数据库,针对每条记录,Key的长度≤896 Byte,Value的长度<4 MB。

  • 单版本数据库,针对每条记录,Key的长度≤1 KB,Value的长度<4 MB。

  • 每个应用程序最多支持同时打开16个键值型分布式数据库。

  • 键值型数据库事件回调方法中不允许进行阻塞操作,例如修改UI组件。

开发步骤

  1. 创建 KVManager 管理器,用于管理数据库

  2. 通过 KVManager 创建数据库,本文创建 SingleKVStore 类型数据库

  3. 保存数据

  4. 根据key获取value

  5. 根据key删除数据

  6. 通过 KVManager 关闭数据库

导入模块

import { distributedKVStore } from '@kit.ArkData';

创建 KVManager 管理器

创建 KVManager 数据库管理器,用于管理数据库,如:创建数据库、关闭数据库

createKVManager(config: KVManagerConfig): KVManager

参数:

  • config:类型:KVManagerConfig,必填,提供KVManager实例的配置信息,包括调用方的包名(不能为空)和用户信息。

返回值:KVManager对象

例子

public initKVManager(bundleName:string):void{
  const kvManagerConfig: distributedKVStore.KVManagerConfig = {
    context: getContext(),
    bundleName: bundleName,
  }
  try {
    this.kvManager = distributedKVStore.createKVManager(kvManagerConfig)
  } catch (e) {
    let error = e as BusinessError;
    console.error(TAG,`创建失败,错误码:${error.code},信息:${error.message}`);
  }
}

KVManagerConfig

提供KVManager实例的配置信息,包括调用方的包名和应用的上下文。

包含以下属性:

  • context:类型:BaseContext,必填,应用的上下文,一般为 getContext()

  • bundleName:类型:string,必填,包名,详见链接

SingleKVStore单版本数据库

单版本数据库,数据不分设备,设备之间修改相同的Key会覆盖

创建数据库

通过 KVManager 对象创建数据库

接口1

通过指定options和storeId,创建并获取分布式键值数据库,使用callback异步回调。

getKVStore<T>(storeId: string, options: Options, callback: AsyncCallback<T>): void

参数:

  • storeId:类型:string,必填,数据库唯一标识符,长度不大于 128,且只能包含 字母、数字 或 下划线_。

  • options:类型:Options,必填,创建分布式键值实例的配置信息。

  • callback:类型:AsyncCallback<T>,必填,回调函数。返回创建的分布式键值数据库实例(根据kvStoreType的不同,可以创建SingleKVStore实例和DeviceKVStore实例)。

例子

public initKVStore(storeId:string){
  const options: distributedKVStore.Options = {
    createIfMissing: true, // 当数据库文件不存在时创建数据库
    encrypt: false, // 数据库文件不加密
    backup: false, // 不备份
    autoSync: false, // 不自动同步
    kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, // 单版本数据库。 数据不分设备,设备之间修改相同的Key会覆盖
    securityLevel: distributedKVStore.SecurityLevel.S1, // 安全级别为低级别,数据的泄露、篡改、破坏、销毁可能会给个人或组织导致 有限的不利影响。
  };
  this.kvManager.getKVStore(storeId, options, (err: BusinessError, store: distributedKVStore.SingleKVStore) => {
    if (err) {
      console.error(TAG,`创建 KVStore 失败,错误码: ${err.code},信息:${err.message}`);
      return;
    }
    this.kvStore = store;
  });
}

Options

用于提供创建数据库的配置信息。有以下属性:

  • createIfMissing:类型:boolean,当数据库文件不存在时是否创建数据库,默认为true,即创建。

  • encrypt:类型:boolean,设置数据库文件是否加密,默认为false,即不加密。

  • backup:类型:boolean,设置数据库文件是否备份,默认为true,即备份。

  • autoSync:类型:boolean,设置数据库是否支持跨设备自动同步。默认为false,即只支持手动同步。配置为true,即只支持在跨设备Call调用实现的多端协同中生效,其他场景无法生效。
    需要权限: ohos.permission.DISTRIBUTED_DATASYNC

  • kvStoreType:类型:KVStoreType,设置要创建的数据库类型,默认为 DEVICE_COLLABORATION,即多设备协同数据库。

  • securityLevel:类型:SecurityLevel,必填,设置数据库安全级别。

  • schema:类型:Schema,设置定义存储在数据库中的值,默认为 undefined,即不使用Schema。

KVStoreType

分布式键值数据库类型枚举

  • DEVICE_COLLABORATION:表示多设备协同数据库。数据库特点: 数据以设备的维度管理,不存在冲突;支持按照设备的维度查询数据。

  • SINGLE_VERSION:表示单版本数据库。数据库特点: 数据不分设备,设备之间修改相同的Key会覆盖。

SecurityLevel

数据库的安全级别枚举。

  • S1:表示数据库的安全级别为低级别,数据的泄露、篡改、破坏、销毁可能会给个人或组织导致 有限的不利影响。
    例如,性别、国籍,用户申请记录等。

  • S2:表示数据库的安全级别为中级别,数据的泄露、篡改、破坏、销毁可能会给个人或组织导致 严重的不利影响。
    例如,个人详细通信地址,姓名昵称等。

  • S3:表示数据库的安全级别为高级别,数据的泄露、篡改、破坏、销毁可能会给个人或组织导致 严峻的不利影响。
    例如,个人实时精确定位信息、运动轨迹等。

  • S4:表示数据库的安全级别为关键级别,业界法律法规中定义的特殊数据类型,涉及个人的最私密领域的信息或者一旦泄露、篡改、破坏、销毁可能会给个人或组织造成 重大的不利影响。
    例如,政治观点、宗教、和哲学信仰、工会成员资格、基因数据、生物信息、健康和性生活状况、性取向等或设备认证鉴权、个人的信用卡等财务信息。

接口2

通过指定options和storeId,创建并获取分布式键值数据库,使用Promise异步回调。

getKVStore<T>(storeId: string, options: Options): Promise<T>

参数:类似接口1

返回值:类型:Promise<T>,Promise对象。返回创建的分布式键值数据库实例(根据kvStoreType的不同,可以创建SingleKVStore 实例和 DeviceKVStore 实例。

关闭数据库

接口1

通过storeId的值关闭指定的分布式键值数据库,使用callback异步回调

closeKVStore(appId: string, storeId: string, callback: AsyncCallback<void>): void

参数:

  • appId:类型:string,必填,应用的 BundleName,不可为空且长度不大于256。

  • storeId:类型:string,必填,要关闭的数据库唯一标识符,长度不大于 128,且只能包含字母数字或下划线_。

  • callback:类型:AsyncCallback<void>,必填,回调函数。当要关闭的数据库成功关闭,err为undefined,否则为错误对象。

例子

public close(bundleName:string,storeId:string){
  this.kvManager.closeKVStore(bundleName, storeId, (err: BusinessError)=> {
    if (err != undefined) {
      console.error(TAG,`关闭数据库失败,错误码:${err.code},信息: ${err.message}`);
      return;
    }
  });
}

接口2

通过storeId的值关闭指定的分布式键值数据库,使用Promise异步回调。

closeKVStore(appId: string, storeId: string): Promise<void>

参数:同上

返回值:Promise<void>,无返回结果的Promise对象。

保存数据

接口1

添加指定类型键值对到数据库,使用callback异步回调。

put(key: string, value: Uint8Array | string | number | boolean, callback: AsyncCallback<void>): void

参数:

  • key:类型:string,必填,要添加数据的Key,不能为空且长度不大于128。

  • value:类型:Uint8Array | string | number | boolean,必填,要添加数据的value,长度不大于128。

  • callback:类型:AsyncCallback<void>,必填,回调函数。数据添加成功,err为undefined,否则为错误对象。

例子

public put(key:string,value:string){
  try {
    this.kvStore.put(key, value, (err: BusinessError) => {
      if (err != undefined) {
        console.error(TAG,`保存数据发生错误,错误码:${err.code},信息:${err.message}`);
        return;
      }
    });
  } catch (error) {
    let err = error as BusinessError;
    console.error(TAG,`保存数据发生错误,错误码:${err.code},信息:${err.message}`);
  }
}

接口2

添加指定类型键值对到数据库,使用Promise异步回调。

put(key: string, value: Uint8Array | string | number | boolean): Promise<void>

参数:同上

返回值: 类型Promise<void>,无返回结果的Promise对象。

根据key获取value

接口1

获取指定键的值,使用callback异步回调。

get(key: string, callback: AsyncCallback<boolean | string | number | Uint8Array>): void

参数:

  • key:类型:string,必填,要查询数据的Key,不能为空且长度不大于MAX_KEY_LENGTH。

  • callback:类型:AsyncCallback<boolean | string | number | Uint8Array>,必填,回调函数。返回获取查询的值。

例子

public async  get(key:string){
  let data!:boolean | string | number | Uint8Array
  try {
    data = await this.kvStore.get(key)
  }catch (error) {
    let err = error as BusinessError;
    console.error(TAG,`获取数据发生错误,错误码:${err.code},信息:${err.message}`);
  }
  return data
}

接口2

获取指定键的值,使用Promise异步回调。

get(key: string): Promise<boolean | string | number | Uint8Array>

参数:

  • key:类型:string,必填,要查询数据的Key,不能为空且长度不大于128

返回值: Promise<Uint8Array | string | boolean | number>,Promise对象。返回获取查询的值。

根据key删除数据

接口1

从数据库中删除指定键值的数据,使用callback异步回调。

delete(key: string, callback: AsyncCallback<void>): void

参数:

  • key:类型:string,必填,要删除数据的Key,不能为空且长度不大于 128

  • callback:类型:AsyncCallback<void>,必填,回调函数。删除指定的数据成功,err为undefined,否则为错误对象。

接口2

从数据库中删除指定键值的数据,使用Promise异步回调。

delete(key: string): Promise<void>

参数:同上

返回值: Promise<void>,无返回结果的Promise对象。

例子

public delete(key:string){
  this.kvStore.delete(key)
    .catch((err: BusinessError) => {
      console.error(TAG,`删除数据失败,错误码:${err.code},信息:${err.message}`);
    });
}

完整代码

UI

import { BusinessError } from '@kit.BasicServicesKit';
import KVManagerUtil from './KVManagerUtil'

const  kvMgr:KVManagerUtil = new KVManagerUtil()
// 包名
const bundleName = 'com.example.myapplication2'
// 数据库名
const storeName = 's_user'

@Entry
@Component
struct KVManagerPage {
  @State putKey :string = ''
  @State putValue :string = ''
  @State getKey :string = ''
  @State delKey :string = ''
  @State msg:string = ''
  build() {
    Column() {
      Button("创建kvManager")
        .fontSize(20)
        .height(50)
        .onClick( e=>{
            kvMgr.initKVManager(bundleName)
        })
      Button("获取SingleKVStore")
        .fontSize(20)
        .height(50)
        .onClick( e=>{
          kvMgr.initKVStore(storeName)
        })

      Row(){
        Text("key:")
          .fontSize(20)
        TextInput({
          text:$$this.putKey
        })
      }
      Row(){
        Text("value:")
          .fontSize(20)
        TextInput({
          text:$$this.putValue
        })
      }
      Button("保存数据")
        .fontSize(20)
        .height(50)
        .onClick( e=>{
          kvMgr.put(this.putKey,this.putValue)
        })
      Row(){
        Text("key:")
          .fontSize(20)
        TextInput({
          text:$$this.getKey
        })
      }
      Row(){
        Text("结果:")
          .fontSize(20)
        Text(this.msg)
          .fontSize(30)
          .height(50)
      }
      Button("获取数据")
        .fontSize(20)
        .height(50)
        .onClick( async e=>{
          const res = await kvMgr.get(this.getKey) as string
          this.msg = res
        })
      Row(){
        Text("key:")
          .fontSize(20)
        TextInput({
          text:$$this.delKey
        })
      }
      Button("删除数据")
        .fontSize(20)
        .height(50)
        .onClick( e=>{
          kvMgr.delete(this.delKey)
        })
      Text("关闭数据库")
        .fontSize(20)
        .height(50)
        .onClick( e=>{
          kvMgr.close(bundleName,storeName)
        })
    }
    .height('100%')
    .width('100%')
  }
}

工具类

在 ets 下创建包 utils,然后创建 KVStoreUtils.ets,内如如下:

import { distributedKVStore } from '@kit.ArkData';
import { BusinessError } from '@kit.BasicServicesKit';

const TAG = "KVManagerUtil--"
export default  class KVManagerUtil{


  kvManager !: distributedKVStore.KVManager;
  kvStore !: distributedKVStore.SingleKVStore

  constructor() {

  }
  /**
   *
   * @param bundleName 包名,如:com.example.myapplication2
   */
  public initKVManager(bundleName:string):void{
    const kvManagerConfig: distributedKVStore.KVManagerConfig = {
      context: getContext(),
      bundleName: bundleName,
    }
    try {
      this.kvManager = distributedKVStore.createKVManager(kvManagerConfig)
    } catch (e) {
      let error = e as BusinessError;
      console.error(TAG,`创建失败,错误码:${error.code},信息:${error.message}`);
    }
  }

  public initKVStore(storeId:string){
    const options: distributedKVStore.Options = {
      createIfMissing: true, // 当数据库文件不存在时创建数据库
      encrypt: false, // 数据库文件不加密
      backup: false, // 不备份
      autoSync: false, // 不自动同步
      kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, // 单版本数据库。 数据不分设备,设备之间修改相同的Key会覆盖
      securityLevel: distributedKVStore.SecurityLevel.S1, // 安全级别为低级别,数据的泄露、篡改、破坏、销毁可能会给个人或组织导致 有限的不利影响。
    };
    this.kvManager.getKVStore(storeId, options, (err: BusinessError, store: distributedKVStore.SingleKVStore) => {
      if (err) {
        console.error(TAG,`创建 KVStore 失败,错误码: ${err.code},信息:${err.message}`);
        return;
      }
      this.kvStore = store;
    });
  }

  public put(key:string,value:string){
    try {
      this.kvStore.put(key, value, (err: BusinessError) => {
        if (err != undefined) {
          console.error(TAG,`保存数据发生错误,错误码:${err.code},信息:${err.message}`);
          return;
        }
      });
    } catch (error) {
      let err = error as BusinessError;
      console.error(TAG,`保存数据发生错误,错误码:${err.code},信息:${err.message}`);
    }
  }
  public async  get(key:string){
    let data!:boolean | string | number | Uint8Array
    try {
      data = await this.kvStore.get(key)
    }catch (error) {
      let err = error as BusinessError;
      console.error(TAG,`获取数据发生错误,错误码:${err.code},信息:${err.message}`);
    }
    return data
  }
  public delete(key:string){
    this.kvStore.delete(key)
      .catch((err: BusinessError) => {
        console.error(TAG,`删除数据失败,错误码:${err.code},信息:${err.message}`);
      });
  }

  public close(bundleName:string,storeId:string){
    this.kvManager.closeKVStore(bundleName, storeId, (err: BusinessError)=> {
      if (err != undefined) {
        console.error(TAG,`关闭数据库失败,错误码:${err.code},信息: ${err.message}`);
        return;
      }
    });
  }
}

原文出处:/show_1GWOfnuF1z.html