HarmonyOS开发(九):数据管理

1、概述

1.1、功能简介

数据管理为开发者提供数据存储、数据管理能力。

它分为两个部分:

  • 数据存储:提供通用数据持久化能力,根据数据特点,分为用户首选项、键值型数据库和关系型数据库。
  • 数据管理:提供高效的数据管理能力,包括权限管理、数据备分恢复、数据共享等

注:应用创建的数据库,都保存到应用少盒,当应用卸载时,数据库也会自动删除。

1.2、运作机制

数据管理模块包括用户首选项、键值型数据管理、关系型数据管理、分布式数据对象和跨应用数据管理。

Interface接口层提供标准JS API接口

Frameworks&System service层负责实现部件数据存储功能

另外还有一些SQLite和其它子系统的依赖

  • 用户首选项:Preferences, 提供轻量级配置数据持久化能力,支持订阅数据变化的通知能力。不支持分布式同步,常常用来保存应用配置信息、用户偏好设置等
  • 键值型数据管理:KV-Store,提供了键值型数据库的读写、加密、手动备份能力。暂不支持分布式功能。
  • 关系型数据管理:RelationalStore,提供了关系型数据库的增删改查、加密、手动备份能力。暂不支持分布式功能。
  • 分布式数据对象:DataObject,独立提供地象型结构数据的分布式能力,暂不支持分布式功能。
  • 跨应用数据管理:DataShare,提供了向其他应用共享以及管理其数据的方法。仅系统应用可用。

2、应用数据持久化概述

应用数据持久化,是指应用将内存中的数据通过文件或数据库的形式保存到设备上。内存中的数据形态通常是任意的数据结构或数据对象,存储介质上的数据形态可能是文本、数据库、二进制文件等。

HarmonyOS标准系统支持典型的存储数据形态有:用户首选项、键值型数据库、关系型数据库

3、用户首选项实现数据持久化

用户首选项为应用提供key-value键值型的数据处理能力,支持应用持久化轻量级数据,并对其进行修改和查询。

Preferences不适合存放过多数据,适用的场景一般为应用保存用户个性化的配置。

3.1、运作机制

用户程序通过JS接口调用用户首选项读写对应的数据文件。开发者可以把用户首选项持久化文件的内容加载到Preferences实例,每个文件唯一对应到一个Preferences实例,系统会通过静态容器把这个实例存储在内存中,直到主动从内存中移除这个实例或删除这个文件。

3.2、使用约束

1、key键为string类型,要求非空且长度不超过80个字节

2、value值为string类型时可以为空,不为空时长度不超过8192个字节

3、内存会随着存储数据量的增大而增大,所以存储的数据应该是轻量级的,建议存储的数据不要超过1万条

3.3、相关接口说明

接口大部分都是异步接口,异步接口都有callback和Promise两种返回形式。以下为callback为例说明

接口名称描述
getPreferences(context:Context,name:string,callback:AsyncCallback<Preferences>):void获取Preferences 实例
put(key:string,value:valueType,callback:AsyncCallback<void>):void把数据写入Preferences实例,可以通过flush把实例进行持 久化
has(key:string,callback:AsyncCallback<boolean>):void检查实例中是否包含指定的key的存储键值对,给定的key不可以为空
get(key:string,defValue:valueType,callback:AsyncCallback<valueType>):void获取指定键对应的值,如果值为null或者非默认值类型,返回默认数据defValue
delete(key:string,callback:AsyncCallback<void>):void从实例中删除指定key的存储键值对
flush(callback:AsyncCallback<void>):void把当前实例中的数据异步存储到用户首选项持久化文件中
on(type:'change',callback?:Callback<{key:string}>):void订阅数据变更,订阅的key的值发生变化,在执行flush方法后,触发callback回调
off(type:'change',callback?:Callback<{key:string}>):void取消订阅数据变更
deletePreferences(context:Context,name:string,callback:AsyncCallback<void>):void从内存中移除指定实例,如果这个实例有对应的持久化文件则同时会把持外化文件删除

3.4、开发步骤

1、导入用户首选项模块

import dataPreferences from '@ohos.data.preferences';

 2、获取Preferences实例,读取指定文件,把数据加载到Preferences实例,用于数据操作

import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
import dataPreferences from '@ohos.data.preferences';export default class EntryAbility extends UIAbility {onCreate(want, launchParam) {}onDestroy() {}onWindowStageCreate(windowStage: window.WindowStage) {// Main window is created, set main page for this abilitytry{dataPreferences.getPreferences(this.context,'mystore',(err,preferences) => {if(err) {console.error(`Failed to get preferences. Code:${err.code},Message:${err.message}`);return;}console.info('Succeeded in getting preferences.')// 进行相关的数据操作})} catch (err) {console.error(`Failed to get preferences. Code:${err.code},Message:${err.message}`);}windowStage.loadContent('pages/Index', (err, data) => {if (err.code) {hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');return;}});}onWindowStageDestroy() {// Main window is destroyed, release UI related resources}onForeground() {// Ability has brought to foreground}onBackground() {// Ability has back to background}
}

在onWindowStageCreate方法中进行读取

3、写入数据

使用put()方法保存数据到缓存的Preferences实例中,在写入数据后如果有必要可以使用flush()方法把Preferences实例的数据存储到持久化文件。

注意:如果键此时已存在则会修改值,如果需要是在键不存在时新增键值对,则需要使用has()进行检查

4、读取数据

使用get()方法获取数据,如果值为null或者非默认值类型,则返回默认数据。

5、删除数据

使用delete()方法删除指定的键值对

6、据的持久化

应用存入数据到Preferences后,可以使用flush()方法实现数据持久化

7、订阅数据更新

使用on(),订阅key值发生变化,flush()执行时,会回调其中的回调方法

8、删除指定文件

使用deletePreferences()方法从内存中移除指定文件对应的Preferences实例,包括内存中的数据。若该Preference存在对应的持久化文件,则同时删除该持久化文件,包括指定文件及其备份文件、损坏文件。

// EntryAbility.tsimport UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
import dataPreferences from '@ohos.data.preferences';export default class EntryAbility extends UIAbility {onCreate(want, launchParam) {}onDestroy() {}onWindowStageCreate(windowStage: window.WindowStage) {// Main window is created, set main page for this abilitytry{dataPreferences.getPreferences(this.context,'mystore',(err,preferences) => {if(err) {console.error(`Failed to get preferences. Code:${err.code},Message:${err.message}`);return;}console.info('Succeeded in getting preferences.')// 进行相关的数据操作globalThis.dataPreferences = preferences;})} catch (err) {console.error(`Failed to get preferences. Code:${err.code},Message:${err.message}`);}windowStage.loadContent('pages/Index', (err, data) => {if (err.code) {hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');return;}});}onWindowStageDestroy() {// Main window is destroyed, release UI related resources}onForeground() {// Ability has brought to foreground}onBackground() {// Ability has back to background}
}
// index.etsimport dataPreferences from '@ohos.data.preferences';
import Prompt from '@system.prompt';
import common from '@ohos.app.ability.common';@Entry
@Component
struct Index {@State message: string = '';@State message1: string = '';dpf:dataPreferences.Preferences = globalThis.dataPreferences;build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold).margin({bottom:10})Text(this.message1).fontSize(50).fontWeight(FontWeight.Bold).margin({bottom:10})Button('put').margin({bottom:15}).onClick(() => {try{this.dpf.has('startup', (err,val) => {if(err) {console.error(`Failed to check data. Code:${err.code}, message:${err.message}`);return;}if (val) {console.info('startup is exists!!')} else {try {this.dpf.put('startup', 'auto', (err) => {if (err) {console.error(`Failed to put data. Code:${err.code}, message:${err.message}`);return;}console.info('succeeded in putting data.')})} catch (err) {console.error(`Failed to put data. Code:${err.code}, message:${err.message}`);}}})}catch(err) {console.error(`Failed to put data. Code:${err.code}, message:${err.message}`);}})Button('get').margin({bottom:15}).onClick(() => {try{this.dpf.get('startup','default',(err,val) => {if(err) {console.error(`Failed to get data. Code:${err.code}, message:${err.message}`);}console.info(`succeeded in getting value of 'startup'. val:${val} `);this.message = val.toString();})}catch (err) {console.error(`Failed to get data. Code:${err.code}, message:${err.message}`);}})Button('delete').margin({bottom:15}).onClick(() => {try{this.dpf.delete('startup', (err) => {if(err) {console.error(`Failed to delete data. Code:${err.code}, message:${err.message}`);return;}console.info('succeeded in deleting the data')})} catch (err) {console.error(`Failed to delete data. Code:${err.code}, message:${err.message}`);}})Button('flush').margin({bottom:15}).onClick(() => {try{this.dpf.flush((err) => {console.error(`Failed to flush data. Code:${err.code}, message:${err.message}`);return;})Prompt.showToast({message: '数据持久化成功!',})} catch (err) {console.error(`Failed to flush data. Code:${err.code}, message:${err.message}`);}})Button('订阅').margin({bottom:15}).onClick(() => {this.dpf.on('change',(key) => {console.info(key + '数据发生变化')})})Button('更新').margin({bottom:15}).onClick(() => {try{this.dpf.put('startup','manual',(err) => {if(err) {console.error(`Failed to put data. Code:${err.code}, message:${err.message}`);return;}})} catch (err){console.error(`Failed to put data. Code:${err.code}, message:${err.message}`);}})Button('deletePreferences').onClick(() => {try{let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;dataPreferences.getPreferences(context,'mystore', (err, val) => {if(err) {console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`);return;}console.info(`successed to delete preferences.`);})} catch (err) {console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`);}})}.width('100%')}.height('100%')}}

4、键值型数据库实现数据持久化

4.1、使用场景介绍

键值型数据库存储键值对形式的数据,一般用来存储的数据没有复杂的关系模型。

4.2、使用约束

1、设备协同数据库,针对每条记录,key的长度小于等于896Byte,value小于4MB

2、单版本数据库,针对每条记录,key的长度小于等于1KB,value小于4MB

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

4、键值型数据库事件回调方法不允许进行阻塞操作

4.3、相关接口说明

接口大部分是异步操作,异步接口都有callback和Promise两种形式

接口名称描述
createKVManager(config: KVManagerConfig): KVManager创建一个KVManager对象实例,用于管数据库对象
getKVStore<T>(storeId:string,options:Options,callback:AsyncCallback<T>):void指定Options和storeId,创建并得到指定类型的KVStore数据库
put(key:string,value:Uint8Array|string|number|boolean,callback:AsyncCallback<void>):void添加指定类型的键值对到数据库
get(key:string,callback:AsyncCallback<Uint8Array|string|number|boolean>):void 获取指定键对应的值
delete(key:string,callback:AsyncCallback<void>):void从数据库中删除指定键值数据

4.4、开发步骤

 1、获取一个KVManager实例

在EntryAbility.ts中onCreate()或onWindowStageCreate()中创建。

onWindowStageCreate(windowStage: window.WindowStage) {// Main window is created, set main page for this ability// KVManagerConfiglet context = this.context;const KvManagerConfig = {context: context,bundleName: 'com.xiaoxie'};try{let kvManager = distributedKVStore.createKVManager(KvManagerConfig);console.info('Succeeded in create KVManager.')globalThis.kvManager = kvManager;} catch (err){console.error(`Failed to create KVManager, Code:${err.code},Message:${err.Message}`);}windowStage.loadContent('pages/KVStore', (err, data) => {if (err.code) {hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');return;}});}

2、创建并获取键值数据库

3、调用put()方法向键值数据库中插入数据,当我们据时key值存在则会修改其值,否则新增一条数据

4、调用get()方法获取指定键值

5、调用delete()方法删除指定键值的数据

// KVStore.ets
import distributedKVStore from '@ohos.data.distributedKVStore';
import Prompt from '@system.prompt';const options = {createIfMissing: true,  // 当数据库文件不存在的时候是否创建,默认创建encrypt: false, // 设置数据库文件是否加密,默认不加密backup: false, // 设置数据库文件是否备份,默认备份kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, // 设置要创建数据库的类型,默认为多设备协同securityLevel: distributedKVStore.SecurityLevel.S2  // 设置数据库的安全级别
};@Entry
@Component
struct KVStore {@State message: string = '';kvManager:distributedKVStore.KVManager = globalThis.kvManagerkvStore:distributedKVStore.SingleKVStore = undefined;build() {Row() {Column() {Text(this.message).fontSize(20).fontWeight(FontWeight.Bold).margin({bottom:10})Button('1、创建并获取键值数据库').width('50%').margin({bottom:10}).onClick(() => {try{this.kvManager.getKVStore('storeId',options,(err,kvStore:distributedKVStore.SingleKVStore) => {if(err) {console.error(`Failed to get KVStore, Code:${err.code},Message:${err.message}`);return;}Prompt.showToast({message: '获取键值数据库成功!',duration: 1500})this.kvStore = kvStore;});} catch (e) {console.error(`Failed to get KVStore, Code:${e.code},Message:${e.message}`);}})Button('2、向键值数据库插入数据').width('50%').margin({bottom: 10}).onClick(() => {try{if(this.kvStore) {this.kvStore.put('test_key','test_value',(err) => {if(err) {console.error(`Failed to put data, Code:${err.code},Message:${err.message}`);return;}Prompt.showToast({message: '向键值数据加中插入数据成功!',duration: 1500})})} else {Prompt.showToast({message: '错误:请先获取数据库!',duration: 1500})}} catch (e) {console.error(`Failed to put data, Code:${e.code},Message:${e.message}`);}})Button('3、获取指定键的值').width('50%').margin({bottom:10}).onClick(() => {try{if(this.kvStore) {this.kvStore.get('test_key',(err,data) => {if(err) {this.message = '';console.error(`Failed to get data, Code:${err.code},Message:${err.message}`);return;}this.message = '';this.message = data.toString();})} else {Prompt.showToast({message: '错误:请先获取数据库!',duration: 1500})}} catch (e) {console.error(`Failed to get data, Code:${e.code},Message:${e.message}`);}})Button('4、删除指定键值数据').width('50%').onClick(() => {try{if(this.kvStore) {this.kvStore.delete('test_key',(err) => {if(err) {console.error(`Failed to delete data, Code:${err.code},Message:${err.message}`);return;}Prompt.showToast({message: '删除指定键值数据成功!',duration: 1500})})} else {Prompt.showToast({message: '错误:请先获取数据库!',duration: 1500})}} catch (e){console.error(`Failed to delete data, Code:${e.code},Message:${e.message}`);}})}.width('100%')}.height('100%')}
}

5、关系型数据库实现数据持久化

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

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

相关文章

Bean的加载控制

Bean的加载控制 文章目录 Bean的加载控制编程式注解式ConditionalOn*** 编程式 public class MyImportSelector implements ImportSelector {Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {try {Class<?> clazz Class.forName("…

UCore-OS实验Lab0

实验内容&#xff1a;搭建ucore-os的实验环境 实验准备内容&#xff1a;vmware虚拟机&#xff0c;ubuntu22.04镜像&#xff0c;qemu7.0.0源码 ucore代码地址 GitHub - chyyuu/os_kernel_lab at x86-32 实验步骤&#xff1a; 在vmware中安装ubuntu&#xff0c;因为我个人喜欢…

openEuler学习04-ssl升级到openssl-1.1.1w

当前环境ssl的版本是 1.1.1f &#xff0c;计划升级到openssl-1.1.1w [roottest ~]# more /etc/os-release NAME"openEuler" VERSION"20.03 (LTS-SP3)" ID"openEuler" VERSION_ID"20.03" PRETTY_NAME"openEuler 20.03 (LTS-SP3)&q…

ES6 Promise的用法,async/await异步处理同步化

文章目录 一、什么是promise &#xff1f;二、await / async ES7的新规范&#xff0c;异步处理同步化 一、什么是promise &#xff1f; promise是解决异步的方法&#xff0c;本质上是一个构造函数&#xff0c;可以用它实例化一个对象。对象身上有resolve、reject、all&#xff…

java学习part33Date

1.Jdk8之前 1.1当前系统时间 1.2.Date类 1.2.1util.date 两个构造器两个方法 1.2.2sql.date 1.3SimpleDateFormat日期格式 1.4Calendar日历 147-常用类与基础API-JDK8之前日期时间API的使用&#xff1a;Date、SimpleDateFormat、Calendar_哔哩哔哩_bilibili 2.Jdk8 2.1本地时…

【C语言学习疑难杂症】第6期:C语言中如何打印一些特殊字符,比如打印扩展ascii码字符

首先我们来看下ascii表和ascii拓展表: ascii表中的字符只有128个,是从0-127,而拓展ascii表的内容是128-255。拓展表中它们都是一些特殊的字符,如果我们想答应ascii拓展码中的一些字符应该要怎么操作呢? 比如下面的代码: unsigned char a = 176, b = 219;printf("%…

Nginx反向代理和负载均衡详细教程

1、Nginx反向代理概述 关于正向代理和反向代理&#xff0c;我们在前面的章节已经通过一张图给大家详细的介绍过了&#xff0c;简而言之就是正向代理代理的对象是客户端&#xff0c;反向代理代理的是服务端&#xff0c;这是两者之间最大的区别。 Nginx即可以实现正向代理&#x…

游戏被流量攻击会有什么样的影响,该用什么样的防护方式去处理

德迅云安全-领先云安全服务与解决方案提供商德迅云游戏盾专门针对游戏进行防护&#xff0c;可免费提供防护方案~ 如果游戏被流量攻击会产生以下影响&#xff1a; 服务器过载&#xff1a;流量攻击会导致游戏服务器接收到的请求数量急剧增加&#xff0c;超出服务器的处理能力。这…

ESP32-Web-Server编程综合项目1-结合 Web Server 实现 WiFi 配网和网页 OTA 更新

ESP32-Web-Server编程综合项目1-结合 Web Server 实现 WiFi 配网和网页 OTA 更新 概述 前述的内容多是一个个小功能的演示&#xff0c;本章节讲述一些实际项目中使用到的综合项目。 首先要讲述的案例是通过ESP32 上的 Web Server 实现对 ESP32 的 WiFi 配网和网页 OTA 更新功…

探究两个互联网时代的差异,Web 2.0 与 Web 3.0 区别

Web 2.0 的特征 首先我们来了解一下 Web 2.0 的特征都有哪些。 用户生成内容&#xff1a;Web 2.0 时代以用户生成内容为特征&#xff0c;用户可以轻松地在网络上分享、创建和编辑信息。社交媒体平台、博客等网站的兴起使得用户成为信息的创造者&#xff0c;网络逐渐从被动浏览…

增强现实技术革新零售业:提升购物体验的未来技术

增强现实&#xff08;AR&#xff09;技术正在改变零售业的面貌&#xff0c;为消费者提供了全新的购物体验。本文将探讨AR技术在零售行业中的应用&#xff0c;以及它如何改变传统的购物方式。 首先&#xff0c;AR技术允许消费者在现实世界中查看虚拟的产品展示。在服装和家具行业…

使用Redis构建任务队列

文章目录 第1关&#xff1a;先进先出任务队列第2关&#xff1a;优先级任务队列第3关&#xff1a;定时任务队列 第1关&#xff1a;先进先出任务队列 编程要求 在Begin-End区域编写 add_task(task_name) 函数&#xff0c;实现将任务加入队列的功能&#xff0c;具体参数与要求如下…

tomcat控制台中文信息显示乱码

问题现象 我的tomcat版本是10.1版本。 在cmd下启动tomcat&#xff0c;会新打开控制台输出窗口&#xff1a; 控制台窗口输出的中文信息是乱码&#xff1a; 问题原因 产生这个问题的原因是&#xff1a;控制台窗口的编码和输出到控制台窗口的日志信息编码不一致。 查看tomc…

Linux 基础命令

1 Linux 基础 1.1 用户类型 1.2 终端 Terminal 设备终端&#xff1a;键盘&#xff0c;鼠标&#xff0c;显示器 1.2.1 终端类型 1.2.2 查看当前的终端设备 tty 命令可以查看当前所在的终端 范例&#xff1a; # tty 可以查看当前所在的终端 $ tty /dev/pts/1 $ who am i ro…

ChatGPT有什么新奇的使用方式?

2023&#xff0c;ChatGPT几乎席卷了所有行业&#xff0c;并且具有不可测量的巨大潜力等着我们去挖掘。 越来越多人对ChatGPT的应用产生兴趣&#xff0c;知乎上“ChatGPT有什么新奇的使用方式&#xff1f;”这一个热门话题的兴起就是最好的证明。 写作&#xff0c;毫无疑问&…

SmartSoftHelp8,数据库字段详细文档自动生成工具

数据库开发文档自动生成 包括数据库设计详细信息&#xff1a; 数据库字段名称&#xff0c;数据类型&#xff0c;大小&#xff0c;是否主键&#xff0c;说明等 一键自动生成开发需求文档 导出html 格式方便查询 下载地址 https://pan.baidu.com/s/1zBgeYsqWnSlNgiKPR2lUYg…

目标检测算法改进系列之添加变核卷积AKConv模块

AKConv变核卷积 KConv的主要思想&#xff1a;AKConv&#xff08;可变核卷积&#xff09;主要提供一种灵活的卷积机制&#xff0c;允许卷积核具有任意数量的参数和采样形状。这种方法突破了传统卷积局限于固定局部窗口和固定采样形状的限制&#xff0c;从而使得卷积操作能够更加…

【iOS控件】—— UIPickerView的使用

【iOS控件】—— UIPickerView的使用 一. 简述UIPickerView1. 什么是UIPickerView2. UIPickerView遵守的协议 二. 测试Demo三. 总结 一. 简述UIPickerView 先看一下UIPickerView的效果图&#xff1a; 1. 什么是UIPickerView UIPickerView是iOS平台上的一个用户界面元素&am…

Excel导入组件的封装以及使用页面点击弹出该弹框

封装的组件 <template><el-dialogwidth"500px"title"员工导入":visible"showExcelDialog"close"$emit(update:showExcelDialog, false)"><el-row type"flex" justify"center"><div class&q…

JVM:强软弱虚四种引用

下面依次解释五种引用 一、强引用 把一个对象赋值给一个引用变量&#xff0c;就相当于把这个对象的强引用放到变量中。 只要对象可达&#xff0c; GC一定不会回收这个对象&#xff08;A1&#xff09; 二、软引用 当一个对象&#xff08;A2&#xff09;没有强引用时&#xff…