【鸿蒙HarmonyOS NEXT】数据存储之分布式键值数据库

news2024/11/17 21:21:57

【鸿蒙HarmonyOS NEXT】数据存储之分布式键值数据库

  • 一、环境说明
  • 二、分布式键值数据库介绍
  • 三、示例代码加以说明
  • 四、小结

一、环境说明

  1. DevEco Studio 版本:
    在这里插入图片描述

  2. API版本:以12为主
    在这里插入图片描述

二、分布式键值数据库介绍

KVStore简介

分布式键值数据库为应用程序提供不同设备间数据库的分布式协同能力。通过调用分布式键值数据库各个接口,应用程序可将数据保存到分布式键值数据库中,并可对分布式键值数据库中的数据进行增加、删除、修改、查询、同步等操作。该模块提供以下分布式键值数据库相关的常用功能:

  • KVManager:分布式键值数据库管理实例,用于获取数据库的相关信息。
  • KVStoreResultSet:提供获取数据库结果集的相关方法,包括查询和移动数据读取位置等。
  • Query:使用谓词表示数据库查询,提供创建Query实例、查询数据库中的数据和添加谓词的方法。
  • SingleKVStore:单版本分布式键值数据库,不对数据所属设备进行区分,提供查询数据和同步数据的方法。
  • DeviceKVStore:设备协同数据库,继承自SingleKVStore,以设备维度对数据进行区分,提供查询数据和同步数据的方法。

应用场景:

键值型数据库存储键值对形式的数据,当需要存储的数据没有复杂的关系模型,比如存储商品名称及对应价格、员工工号及今日是否已出勤等,由于数据复杂度低,更容易兼容不同数据库版本和设备类型,因此推荐使用键值型数据库持久化此类数据。

常用接口说明:

键值型数据库持久化功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,其他接口请查看官网:分布式键值数据库接口说明在这里插入图片描述

三、示例代码加以说明

沿用【鸿蒙HarmonyOS NEXT】页面之间相互传递参数博文中的代码,进行测试。
使用场景说明用户信息需要在整个app中全局获取到,需要将用户信息在登录的时候存储到分布式键值数据库中。

代码改写如下:

  1. LoginPage完整代码如下:
    import { router } from '@kit.ArkUI';
    
    // 引入Context相关
    import { common } from '@kit.AbilityKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    
    // 引入preferences相关
    import { distributedKVStore } from '@kit.ArkData';
    import { util } from '@kit.ArkTS';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    // 定义ihlog日志常量相关
    const TAG: string = '[LoginPage_Context]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    @Preview
    @Entry
    @Component
    struct LoginPage {
      @State message: string = '登录页';
      @State btnMsg: string = '登录';
      @State account: string = ''; // 账号状态变量
      @State password: string = ''; // 密码状态变量
      @State isShowProgress: boolean = false; // 显示进度指示器的状态变量
      // 获取Context
      private context = getContext(this) as common.UIAbilityContext;
    
      build() {
        Column() {
          Text(this.message)
            .id('HelloWorld')
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .width('100%')
            .height(50)
            .textAlign(TextAlign.Center)
            .backgroundColor(0xF1F3F5)
    
          Image($r('app.media.startIcon'))
            .width(150)
            .height(150)
            .margin({ top: 40, bottom: 40 })
    
          TextInput({ placeholder: '请输入手机号' })
            .maxLength(11)// 最大长度
            .type(InputType.Number)// 输入类型为数字
            .inputStyle()// 应用自定义样式
            .onChange((value: string) => {
              this.account = value; // 更新账号状态
            })
          Line().lineStyle() // 应用自定义Line样式
    
          // 密码输入框
          TextInput({ placeholder: '请输入密码' })
            .maxLength(12)// 最大长度
            .type(InputType.Password)// 输入类型为密码
            .inputStyle()// 应用自定义样式
            .onChange((value: string) => {
              // TODO: 生产环境需要使用正则表达式对手机号进行验证
              this.password = value; // 更新密码状态
            })
          Line().lineStyle() // 应用自定义Line样式
    
    
          Button(this.btnMsg)
            .width('80%')
            .margin({ top: 100 })
            .height(50)
            .onClick(() => {
              if (this.account === undefined || this.account === '') {
                console.info('请输入账号')
                return
              }
    
              if (this.password === undefined || this.password === '') {
                console.info('请输入密码')
                return
              }
    
              // 使用ArkData分布式键值数据库 以Key/Value形式存储用户信息数据
              let kvManager: distributedKVStore.KVManager | undefined = undefined;
              const kvManagerConfig: distributedKVStore.KVManagerConfig = {
                context: this.context,
                bundleName: 'com.suben.hellotest'
              };
              try {
                // 创建KVManager实例
                kvManager = distributedKVStore.createKVManager(kvManagerConfig);
                console.info('Succeeded in creating KVManager.');
              } catch (e) {
                let error = e as BusinessError;
                console.error(`Failed to create KVManager. Code:${error.code},message:${error.message}`);
              }
              // 继续创建获取数据库
              if (kvManager !== undefined) {
                kvManager = kvManager as distributedKVStore.KVManager;
                //进行后续操作
                let kvStore: distributedKVStore.SingleKVStore | undefined = undefined;
    
                try {
                  const options: distributedKVStore.Options = {
                    createIfMissing: true,
                    encrypt: false,
                    backup: false,
                    autoSync: false,
                    // kvStoreType不填时,默认创建多设备协同数据库
                    kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
                    // 多设备协同数据库:kvStoreType: distributedKVStore.KVStoreType.DEVICE_COLLABORATION,
                    securityLevel: distributedKVStore.SecurityLevel.S1
                  };
    
                  kvManager.getKVStore<distributedKVStore.SingleKVStore>('storeId', options,
                    (err, store: distributedKVStore.SingleKVStore) => {
                      if (err) {
                        console.error(`Failed to get KVStore: Code:${err.code},message:${err.message}`);
                        return;
                      }
                      console.info('Succeeded in getting KVStore.');
                      kvStore = store; // 请确保获取到键值数据库实例后,再进行相关数据操作
    
                      if (kvStore !== undefined) {
                        kvStore = kvStore as distributedKVStore.SingleKVStore;
                        //进行后续操作,如将用户信息插入数据库中进行保存
                        const KEY_ACCOUNT = 'account';
                        const VALUE_ACCOUNT = this.account;
                        const KEY_PASSWORD = 'password';
                        const VALUE_PASSWORD = this.password;
                        try {
                          kvStore.put(KEY_ACCOUNT, VALUE_ACCOUNT, (err) => {
                            if (err !== undefined) {
                              console.error(`Failed to put account data. Code:${err.code},message:${err.message}`);
                              return;
                            }
                            console.info('Succeeded in putting account data.');
                          });
                          kvStore.put(KEY_PASSWORD, VALUE_PASSWORD, (err) => {
                            if (err !== undefined) {
                              console.error(`Failed to put password data. Code:${err.code},message:${err.message}`);
                              return;
                            }
                            console.info('Succeeded in putting password data.');
                          });
                        } catch (e) {
                          let error = e as BusinessError;
                          console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
                        }
                      }
                    });
                } catch (e) {
                  let error = e as BusinessError;
                  console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
                }
              }
    
              // 跳转到首页
              router.pushUrl({
                url: 'pages/HomePage',
                params: {
                  account: this.account,
                  password: this.password
                }
              })
            })
        }
        .height('100%')
        .width('100%')
        .padding(0)
      }
    }
    
    // TextInput组件的自定义样式扩展
    @Extend(TextInput)
    function inputStyle() {
      .placeholderColor(Color.Gray) // 占位符颜色
      .height(50) // 输入框高度
      .fontSize(15) // 字体大小
      .backgroundColor(0xF1F3F5) // 背景颜色
      .width('90%') // 宽度为父组件的100%
      .padding({ left: 12 }) // 左侧填充
      .margin({ top: 15 }) // 上方边距
    }
    
    // Line组件的自定义样式扩展
    @Extend(Line)
    function lineStyle() {
      .width('100%') // 宽度为父组件的100%
      .height(1) // 高度
      .backgroundColor(0xF1F3F5) // 背景颜色
    }
    
  2. HomePage完整代码如下:
    import { router } from '@kit.ArkUI';
    import { distributedKVStore } from '@kit.ArkData';
    import { common } from '@kit.AbilityKit'
    import { util } from '@kit.ArkTS';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    // 定义ihlog日志常量相关
    const TAG: string = '[HomePage_Context]';
    const DOMAIN_NUMBER: number = 0xFF01;
    
    @Preview
    @Entry
    @Component
    struct HomePage {
      @State message: string = '首页';
      // 获取前一个页面传递过来的数据
      @State account: string = ''
      @State password: string = ''
      // 获取Context
      private context = getContext(this) as common.UIAbilityContext;
    
      aboutToAppear(): void {
        // 使用ArkData KV数据库 获取用户数据
        // this.account = this.dataPreferences.getSync('account', 'default').toString(); // 'default' 可以换成其他的,如null,但这个参数必须给
        // hilog.info(DOMAIN_NUMBER, TAG, `account: ${this.account}`);
        // // 当获取的值为带有特殊字符的字符串时,需要将获取到的Uint8Array转换为字符串
        // let uInt8Array2 : preferences.ValueType = this.dataPreferences.getSync('password', new Uint8Array(0));
        // let textDecoder = util.TextDecoder.create('utf-8');
        // this.password = textDecoder.decodeToString(uInt8Array2 as Uint8Array);
        // hilog.info(DOMAIN_NUMBER, TAG, `password: ${this.password}`);
        let kvManager: distributedKVStore.KVManager | undefined = undefined;
        const kvManagerConfig: distributedKVStore.KVManagerConfig = {
          context: this.context,
          bundleName: 'com.suben.hellotest'
        };
        try {
          // 创建KVManager实例
          kvManager = distributedKVStore.createKVManager(kvManagerConfig);
          console.info('Succeeded in creating KVManager.');
        } catch (e) {
          let error = e as BusinessError;
          console.error(`Failed to create KVManager. Code:${error.code},message:${error.message}`);
        }
        // 继续创建获取数据库
        if (kvManager !== undefined) {
          kvManager = kvManager as distributedKVStore.KVManager;
          //进行后续操作
          let kvStore: distributedKVStore.SingleKVStore | undefined = undefined;
    
          try {
            const options: distributedKVStore.Options = {
              createIfMissing: true,
              encrypt: false,
              backup: false,
              autoSync: false,
              // kvStoreType不填时,默认创建多设备协同数据库
              kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
              // 多设备协同数据库:kvStoreType: distributedKVStore.KVStoreType.DEVICE_COLLABORATION,
              securityLevel: distributedKVStore.SecurityLevel.S1
            };
    
            kvManager.getKVStore<distributedKVStore.SingleKVStore>('storeId', options,
              (err, store: distributedKVStore.SingleKVStore) => {
                if (err) {
                  console.error(`Failed to get KVStore: Code:${err.code},message:${err.message}`);
                  return;
                }
                console.info('Succeeded in getting KVStore.');
                kvStore = store; // 请确保获取到键值数据库实例后,再进行相关数据操作
                if (kvStore !== undefined) {
                  kvStore = kvStore as distributedKVStore.SingleKVStore;
    
                  const KEY_ACCOUNT = 'account';
                  const KEY_PASSWORD = 'password';
                  // 获取账户
                  kvStore.get(KEY_ACCOUNT, (err, data) => {
                    if (err != undefined) {
                      console.error(`Failed to get ACCOUNT data. Code:${err.code},message:${err.message}`);
                      return;
                    }
                    console.info(`Succeeded in getting ACCOUNT data. Data:${data}`);
                    this.account = data.toString()
                  });
                  //获取密码
                  kvStore.get(KEY_PASSWORD, (err, data) => {
                    if (err != undefined) {
                      console.error(`Failed to get PASSWORD data. Code:${err.code},message:${err.message}`);
                      return;
                    }
                    console.info(`Succeeded in getting PASSWORD data. Data:${data}`);
                    this.password = data.toString()
                  });
    
                }
              });
          } catch (e) {
            let error = e as BusinessError;
            console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`);
          }
        }
      }
    
      build() {
        Column() {
          Text(this.message)
            .fontSize(30)
            .width('100%')
            .height(50)
            .textAlign(TextAlign.Center)
            .backgroundColor(0xF1F3F5)
    
          Blank().height(120)
    
          Text(`接收到的用户名:${this.account}`)
            .fontSize(20)
            .width('100%')
            .height(50)
            .padding({ left: 12, right: 12 })
    
          Text(`接收到的密码:${this.password}`)
            .fontSize(20)
            .width('100%')
            .height(50)
            .padding({ left: 12, right: 12 })
    
    
          Button('返回上一页')
            .width('80%')
            .margin({ top: 120 })
            .height(50)
            .onClick(() => {
              // 返回登录页面
              router.showAlertBeforeBackPage({ message: '确认返回上一页吗?' })
              router.back({
                url: 'pages/LoginPage',
                params: {
                  msg: 'homepage'
                }
              })
            })
        }
        .height('100%')
        .width('100%')
      }
    }
    
    

测试步骤如下:
3. 打开模拟器,并将代码部署到模拟器上,当模拟器正常运行代码后,输入用户名和密码
在这里插入图片描述

  1. 点击手机模拟器上应用的登录按钮,跳转到了首页,然后再从首页返回登录页,查看控制台日志,内容如截图红色框或者首页文字所示:
    在这里插入图片描述

四、小结

通过上述的说明和示例演示,相信大家已经很清楚分布式键值数据库读写数据的用法了。细心的读者朋友可能会问,如何删除数据呢?或者有何约束和限制呢?感兴趣的读者朋友可以对照鸿蒙官网上的示例尝试下,看看使用键值型数据库持久化此类数据是否可以正常运行呢?欢迎大家的留言,我们在留言区进行讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2176337.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手机电脑无缝对接,虫洞软件让多屏协同触手可及

在数字化时代&#xff0c;我们的日常生活和工作越来越依赖于电子设备&#xff0c;尤其是智能手机和电脑。但你是否曾因在手机和电脑之间频繁切换而感到烦恼&#xff1f;现在&#xff0c;有了虫洞软件&#xff0c;这一切都将成为过去式。 虫洞——电脑与手机的桥梁 虫洞软件&a…

Kubernetes整体架构与核心组件

一个 Kubernetes 集群的机器节点有两种角色—— Master 和 Node&#xff0c;都可由一个或多个节点组成&#xff0c;且同一个节点可以既是 Master 也是 Node。其中 Master 节点负责全局决策、资源调度、Node 与 Pod 管理&#xff0c;等等&#xff0c;属于管控节点&#xff1b;No…

【unity进阶知识4】封装unity协程工具,避免 GC(垃圾回收)

文章目录 前言封装协程工具类&#xff0c;避免 GC&#xff08;垃圾回收&#xff09;使用1.使用默认方式使用协程2.使用自定义的 CoroutineTool 工具类来等待不同的时间 完结 前言 在 Unity 中&#xff0c;使用 yield return null 、yield return new WaitForEndOfFrame()等会导…

人物型Agent开发(文心智能体平台创作分享)

开发平台&#xff1a;文心智能体平台AgentBuilder | 想象即现实 目录 一、开发灵感 &#xff08;一&#xff09;打破刻板印象 &#xff08;二&#xff09;以古鉴今&#xff0c;探索人性与情感 二、角色分析与设定 &#xff08;一&#xff09;西门庆特质 &#xff08;二&a…

我的深度学习笔记

传统观念认为&#xff1a;在不考虑算力的情况下&#xff0c;网络越深&#xff0c;其准确率就越高&#xff0c;最直接的方法就是把网络设计的越深越好。 事实上&#xff1a;随着网络的层数不断加深&#xff0c;当达到一定的书目之后&#xff0c;训练精度和测试精度都有下降&…

第十三届蓝桥杯真题Java c组C.纸张尺寸(持续更新)

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;蓝桥杯关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 【问题描述】 在 ISO 国际标准中定义了 A0 纸张的大小为 1189mm 841mm&#…

AI运用在营销领域的经典案例及解析

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 在前面一篇文章当中&#xff0c;我给大家介…

[Redis][典型运用][缓存]详细讲解

目录 0.什么是缓存&#xff1f;1.使用Redis作为缓存1.为什么用&#xff1f;2.如何用&#xff1f; 2.缓存的更新策略0.前言1.定期生成2.实时生成 3.缓存相关问题1.缓存预热(Cache Preheating)2.缓存穿透(Cache Penetration)3.缓存雪崩(Cache Avalanche)4.缓存击穿(Cache Breakdo…

一种多版本、多人并行开发GIT分支管理规范

首发公众号&#xff1a; 赵侠客 引言 作为开发者每天在写代码的同时也在写BUG&#xff0c;所以一方面需要开发新的需求&#xff0c;另一方面还要填自己以前挖的坑。目前主流程序员都在使用GIT来管理自己的代码&#xff0c;当GIT仓库有多人维护或者项目有多个版本同时迭代开发时…

c++进阶学习--------多态

前言 需要声明的&#xff0c;本节课件中的代码及解释都是在vs2022下的x86程序中&#xff0c;涉及的指针都是4bytes。 如果要其他平台下&#xff0c;部分代码需要改动。 比如&#xff1a;如果是x64程序&#xff0c;则需要考虑指针是8bytes问题等等 1. 多态的概念 1.1 概念 …

.NET内网实战:白名单文件反序列化执行命令

01阅读须知 此文所节选自小报童《.NET 内网实战攻防》专栏&#xff0c;主要内容有.NET在各个内网渗透阶段与Windows系统交互的方式和技巧&#xff0c;对内网和后渗透感兴趣的朋友们可以订阅该电子报刊&#xff0c;解锁更多的报刊内容。 02基本介绍 本文内容部分节选自小报童…

【易社保-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

Java泛型方法的定义和使用、泛型类、泛型接口、泛型方法、通配符、泛型的上界与下界

文章目录 一、包装类1.1、基本数据类型和对应的包装类1.2、自动装箱和自动拆箱 二、基本介绍2.1、泛型引入背景2.1、什么是泛型2.2、为什么使用泛型 三、常见泛型字母含义四、泛型的使用4.1、泛型类4.2、泛型接口4.3、泛型方法 五、泛型的继承5.1、泛型不具备继承性5.2、何为数…

【Python】递归

专栏文章索引&#xff1a;Python 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 文章内容改自&#xff1a;bilibili博主(又懂啦) 目录 一、递归函数 二、理解递归函数 一、递归函数 一个函数在其函数体内调用函数自身&#xff0c;这样的函数就称为递归函数。递归函数的…

每日一练 2024.9.29(2)

目录 解题思路与代码实现 题目分析 一、解题策略 关键步骤&#xff1a; 二、代码实现 三、代码解析 四、复杂度分析 五、运行示例 示例1&#xff1a; 示例2&#xff1a; 六、总结 解题思路与代码实现 题目分析 这道题目要求我们找到字符串列表 strs 中的相似字符组…

Arch - 架构安全性_验证(Verification)

文章目录 OverView导图1. 引言&#xff1a;数据验证的重要性概述2. 数据验证的基本概念3. 数据验证的层次前端验证后端验证 4. 数据验证的标准做法5. 自定义校验注解6. 校验结果的处理7. 性能考虑与副作用8. 小结 OverView 即使只限定在“软件架构设计”这个语境下&#xff0c…

物理学基础精解【40】

文章目录 矢量积矢量积&#xff08;又称叉积、外积&#xff09;的几何意义一、面积表示二、垂直性三、方向性四、应用实例五、数学表达 矢量积&#xff08;叉积&#xff09;的坐标表示法矢量积的坐标表示法的几何意义矢量积的性质矢量积的应用 矢量积&#xff08;又称叉积、外积…

Linux——k8s组件

kubernetes 使用1.31.1 版本搭建集群核心组件&#xff0c;选择flannel 网络插件为整体集群的运行提供网络通信功能。 flannel 网络插件 kube-flannel kube-flannel-ds-9fgml 1/1 Running 1 (18m ago) 2d21h kube-flannel kube-flannel-ds-ghwbq …

<<迷雾>> 第 3 章 怎样才能让机器做加法 示例电路

全加器示意图 info::操作说明 鼠标单击开关切换开合状态 primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.net/cyjsjdmw-examples/assets/circuit/cyjsjdmw-ch03-01-full-adder.txt 原图 由3个全加器组成的3比特加法机 info::操作说明…

Linux——pod的调度

pod的调度 控制器: rc/rs 副本数量控制器 主要保证pod的数量符合管理员要求&#xff0c;并不会对pod进行额外的管理 以下三种控制器&#xff0c;本质上是服务控制器。具备以下特性&#xff1a; 副本数量的控制服务的滚动更新&#xff08;更新pod&#xff09;支持更新失…