ArkTS - 数据持久化

news2024/9/21 11:05:43

一、概述

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

持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等等。 

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

  • 用户首选项(Preferences):通常用于保存应用的配置信息。数据通过文本的形式保存在设备中,应用使用过程中会将文本中的数据全量加载到内存中,所以访问速度快、效率高,但不适合需要存储大量数据的场景。
  • 键值型数据库(KV-Store):一种非关系型数据库,其数据以“键值”对的形式进行组织、索引和存储,其中“键”作为唯一标识符。适合很少数据关系和业务关系的业务数据存储,同时因其在分布式场景中降低了解决数据库版本兼容问题的复杂度,和数据同步过程中冲突解决的复杂度而被广泛使用。相比于关系型数据库,更容易做到跨设备跨版本兼容。
  • 关系型数据库(RelationalStore):一种关系型数据库,以行和列的形式存储数据,广泛用于应用中的关系型数据的处理,包括一系列的增、删、改、查等接口,开发者也可以运行自己定义的SQL语句来满足复杂业务场景的需要。

二 、用户首选项

用户首选项(Perference)为应用提供 key-value 键值型的数据处理能力,支持应用持久化轻量级数据

说白了,用户首选项就是用来保存和记录用户在操作应用的过程做做出的一些选择或设置。 可以存储一些数据,但基本都是简单类型的数据,主要作用都是存储一些用户设置数据,比如是否是首次登陆,就可以设置一个布尔类型的变量,设值为true或false。

你可以粗暴的将它看作类似于redis的以键值对存储的本地非关系型数据库(NoSql),这样方便你使用与理解。

再或者你可以将它想象成一个用来存储数据的仓库/中转站,可以跨组件的使用这些数据

约束限制 

  • Key键为string类型,要求非空且长度不超过80个字节。
  • 如果Value值为string类型,可以为空,不为空时长度不超过8192个字节。
  • 内存会随着存储数据量的增大而增大,所以存储的数据量应该是轻量级的,建议存储的数据不超过一万条,否则会在内存方面产生较大的开销。

使用步骤

1、导入用户首选项模块

import preferences from '@ohos.data.preferences'

2、获取Perferences实例,读取指定文件

preference.getPreferences(this.context,"MyAppPreferences")
  .then(preferences => {
    //获取成功
  
  })
  .catch(reason => {
    //获取失败

  })

3、 数据操作

//写入数据,如果已经存在则会覆盖,可以利用.has()判断是否存在
preferences.put('key',val)
  .then(() => {
    preferences.flush() //刷到磁盘中
  })
  .catch(reason => {})  //处理异常

//删除数据
preferences.delete('key')
  .then(() => {

  })
  .catch(reason => {

  })

//查询数据,defaultValue是默认值,没有值时就返回这个
preferences.get('key','defaultValue')
  .then(value => {

  })
  .catch(reason => {
    
  })

封装工具类

我们可以将这些功能封装成一个工具类

import preferences from '@ohos.data.preferences'

class PreferencesUtil {

  //map集合存储多个不同的preference
  preferencesMap: Map<string, preferences.Preferences> = new Map;


  //加载一个preference
  async loadPreference(context, name: string) {
    console.log('testTag', `开始加载Preference [${name}]`);

    try { //返回值是一个Promise包裹起来的preference,因此可以使用链式回调函数处理,也可以使用async/await
      let preference = await preferences.getPreferences(context, name)

      this.preferencesMap.set(name, preference)
      console.log('testTag', `加载Preference [${name}]成功`);

      return preference
    } catch (err) {
      console.log('testTag', `加载Preference [${name}]失败`, JSON.stringify(err));
      Promise.reject(`加载Preference [${name}]失败`)
    }

  }

  //获取指定preference并存入键值对数据
  async putPreferenceValue(name: string, key: string, value: preferences.ValueType) {
    if (!this.preferencesMap.has(name)) {
      console.log('testTag', `Preference[${name}]尚未初始化`);

      //结束异步
      Promise.reject("`Preference[${name}]尚未初始化`")
    }

    try {
      let preference = this.preferencesMap.get(name)

      //写入数据
      await preference.put(key, value)

      //刷新磁盘
      preference.flush()

      console.log('testTag', `保存Preferences[${name}:${key}=${value}]成功`)
    } catch (e) {
      console.log('testTag', `保存Preferences[${name}.${key}=${value}]失败`, JSON.stringify(e));
    }
  }

  //获取指定preference的指定数据
  async getPreferenceValue(name: string, key: string, defaultValue: preferences.ValueType) {
    if (!this.preferencesMap.has(name)) {
      console.log('testTag', `Preference[${name}]尚未初始化`);

      //结束异步
      Promise.reject("`Preference[${name}]尚未初始化`")
    }
    try {
      let preference = this.preferencesMap.get(name)

      //读数据
      let value = await preference.get(key, defaultValue)

      console.log('testTag', `获取Preferences[${name}:${key}=${value}]成功`)

      return value

    } catch (e) {
      console.log('testTag', `获取Preferences[${name}.${key}]失败`, JSON.stringify(e));
    }
  }

  //删除指定preference的指定数据
  async deletePreferenceValue(name: string, key: string, defaultValue: preferences.ValueType) {
    isPreferencesHas(this.preferencesMap, name);

    try {
      let preference = this.preferencesMap.get(name)

      //删除数据
      preference.delete(key)

      console.log('testTag', `删除Preferences[${name}.${key}]成功`)

      return

    } catch (err) {
      console.log('testTag', `删除Preferences[${name}.${key}]失败`)
    }
  }
}

const isPreferencesHas = function (preferenceMap: Map<string, preferences.Preferences>, name) {
  if (!this.preferencesMap.has(name)) {
    console.log('testTag', `Preference[${name}]尚未初始化`);

    //结束异步
    Promise.reject("`Preference[${name}]尚未初始化`")
  }
}


const preferencesUtil = new PreferencesUtil()

export default preferencesUtil as PreferencesUtil

示例 

在使用preferences之前肯定要先加载一个preference实例,然后才能使用接下来的增删查功能。

既然要加载,肯定不能是像之前那样让用户点个按钮触发创建,而是最好程序已启动就自动隐式的创建,所以使用生命周期的钩子函数onCreate()方法

在EntryAbility文件中调用加载preference即可(注意这个在预览页中是无法触发该方法的,需要使用模拟器启动程序,而且此页面需要在main_pages.json中注册这个页面

同时我们也希望当index页面一加载完毕后就获取这个刚才加载的preference,所以使用页面的钩子函数aboutToAppear()方法(相当于vue的钩子函数onMounted())

 


三、关系型数据库 - SQLite

关系型数据库基于SQLite组件,适用于存储包含复杂关系数据的场景,比如一个班级的学生信息,需要包括姓名、学号、各科成绩等,又或者公司的雇员信息,需要包括姓名、工号、职位等,由于数据之间有较强的对应关系,复杂程度比键值型数据更高,此时需要使用关系型数据库来持久化保存数据。

关系型数据库对应用提供通用的操作接口,底层使用SQLite作为持久化存储引擎,支持SQLite具有的数据库特性,包括但不限于事务、索引、视图、触发器、外键、参数化查询和预编译SQL语句。 

鸿蒙和安卓一样支持SQLite,你或许会疑问,既然我们已经可以使用用户首选项(Preferences)做数据的持久化处理,那么为什么要使用SQLite?

使用用户首选项(SharedPreferences)是一种轻量级的本地存储方式,适用于存储小量的简单数据,例如用户设置、配置信息等。它对于快速存储和检索简单数据非常方便,但在某些情况下,你可能考虑使用 SQLite 数据库来进行数据持久化处理的原因包括:

  1. 复杂数据结构: 如果你的应用需要存储的数据结构较为复杂,包含多个字段或需要进行多表关联,SQLite 提供了更灵活的表结构和查询语言,使你能够更好地组织和管理数据。

  2. 大量数据存储: 当应用需要存储大量结构化数据时,SQLite 可以更好地处理复杂的数据存储和检索需求。SharedPreferences适用于小型数据,但对于大量的、需要进行查询和排序的数据,SQLite 提供了更强大的功能。

  3. 查询和过滤: 如果你需要进行复杂的数据查询、排序、过滤操作,SQLite 提供了 SQL 查询语言,可以更方便地执行这些操作。

  4. 支持事务: 如果你的应用需要支持事务处理,SQLite 是一个更适合的选择。事务是一种保障数据库操作原子性、一致性、隔离性和持久性的机制。

  5. 多用户支持: 如果你的应用需要支持多用户场景,每个用户有自己的数据,SQLite 提供了更好的多用户数据隔离能力。

就如redis和mysql之间的关系,sqlite不是来取代用户首选项的,他们是互相补充的关系,它们有各自的优势和适用场景。在许多应用中,它们并不是互相排斥的选择,而是可以根据具体需求互相补充使用。

使用步骤

1、使用关系型数据库实现数据持久化,需要获取一个RdbStore

import relationalStore from '@ohos.data.relationalStore'; // 导入模块 
import UIAbility from '@ohos.app.ability.UIAbility';

class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage) {
    const STORE_CONFIG = {
      name: 'RdbTest.db', // 数据库文件名
      securityLevel: relationalStore.SecurityLevel.S1 // 数据库安全级别
    };

    const SQL_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER, SALARY REAL, CODES BLOB)'; // 建表Sql语句

    relationalStore.getRdbStore(this.context, STORE_CONFIG, (err, store) => {
      if (err) {
        console.error(`Failed to get RdbStore. Code:${err.code}, message:${err.message}`);
        return;
      }
      console.info(`Succeeded in getting RdbStore.`);
      store.executeSql(SQL_CREATE_TABLE); // 创建数据表

      // 这里执行数据库的增、删、改、查等操作

    });
  }
}

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

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

相关文章

如何查看崩溃日志

​ 目录 描述 思路 查看ipa包崩溃日志 简单查看手机崩溃信息几种方式 方式1:手机设置查看崩溃日志 方式2: Xocde工具 方式3: 第三方软件克魔助手 环境配置 实时日志 奔溃日志分析 方式四&#xff1a;控制台资源库 线上崩溃日志 线上监听crash的几种方式 方式1: 三…

GEC6818科大讯飞离线语音识别

GEC6818科大讯飞离线语音识别 文章目录 GEC6818科大讯飞离线语音识别一、 下载科大讯飞离线语音SDK二、 解压文件夹后三、与GEC6818开发板一起使用3.1 使用科大讯飞的离线语音在ubantu中运行&#xff0c;作为服务端进行关键字的识别3.2 call.bnf-->hehe.bnf3.3 asr_offine_s…

JavaWeb基础(1)- Html与JavaScript(JavaScript基础语法、变量、数据类型、运算符、函数、对象、事件监听、正则表达式)

JavaWeb基础&#xff08;1&#xff09;- Html与JavaScript(JavaScript基础语法、变量、数据类型、运算符、函数、对象、事件监听、正则表达式) 文章目录 JavaWeb基础&#xff08;1&#xff09;- Html与JavaScript(JavaScript基础语法、变量、数据类型、运算符、函数、对象、事件…

什么是软件安全性测试?如何进行安全测试?

一、什么是软件安全性测试&#xff1f; 软件安全性测试是指对软件系统中的安全漏洞进行检测和评估的过程。其目的是为了确保软件系统在面对各种安全威胁时能够保持其功能的完整性、可用性和机密性。 二、软件安全性测试可以通过以下几个步骤来进行&#xff1a; 1. 需求分析&a…

强化学习8——在冰壶环境中使用策略迭代和价值迭代算法

冰壶环境 环境介绍 OpenAI Gym库中包含了很多有名的环境&#xff0c;冰湖是 OpenAI Gym 库中的一个环境&#xff0c;和悬崖漫步环境相似&#xff0c;大小为44的网格&#xff0c;每个网格是一个状态&#xff0c;智能体起点状态S在左上角&#xff0c;目标状G态在右下角&#xf…

计算机毕业设计----SSM BBS论坛

项目介绍 本项目包含前后台&#xff0c;前台为普通用户登录&#xff0c;后台为管理员登录&#xff1b; 管理员角色包含以下功能&#xff1a; 管理员登录,删除或者编辑用户的帖子,后台管理,友情链接管理,用户管理,版块管理,网站设置,用户设置,版块主题管理等功能。 用户角色…

fpmarkets盘点成功交易者的十个习惯(一)

在交易中能够盈利一次&#xff0c;fpmarkets认为这种情况100%的交易者都会做到&#xff0c;但是要做到每次交易都能盈利&#xff0c;即使是巴菲特也做到&#xff0c;我们只需要做到整体盈利就可以了&#xff0c;那么如何做到呢&#xff1f;今天fpmarkets就总结一下成功交易者的…

斑马斑马跳

欢迎来到程序小院 斑马斑马跳 玩法&#xff1a;行走的斑马&#xff0c;点击鼠标左键斑马左右跳动&#xff0c;左右两侧有大树&#xff0c;和移动的小鸟&#xff0c; 撞到大树和小鸟游戏结束&#xff0c;统计分数&#xff0c;快去斑马跳吧^^。开始游戏https://www.ormcc.com/pl…

2024农历新年是什么时候?电脑如何设置农历新年提醒

元旦的钟声已经远去&#xff0c;2024年的阳历新年就这样悄无声息地开始了。但对于我们很多人来说&#xff0c;真正的“过年”氛围&#xff0c;还得等到农历新年的到来。那么&#xff0c;今年的农历新年究竟是什么时候呢&#xff1f;答案是2月10日。 每当想到农历新年&#xff…

浅析进程优先级(上)

什么是进程优先级&#xff1f; 进程优先级&#xff1a;将处理器资源分配给进程的先后顺序 Linux 中每个进程都有相应的优先级 (优先级可能动态改变) 进程优先级决定进程 何时执行 和 获得处理器的时间 进程优先级通常表现为一个整数值 (数值大小决定优先级高低) Linux 中的…

寻找两个相交链表的相交节点

分析&#xff1a; 如图所示&#xff0c; A 长度为mkB长度为nk张三&#xff0c;李四两人分别从A和B的起始点相同速度出发&#xff0c;无论谁到达终点时&#xff0c;都从另一条队列的起点再次出发。假定起始&#xff0c;张三沿着A走&#xff0c;李四沿着B走。当李四到达终点后&a…

计算机毕业设计选题分享-node.js旅游景点分享网站03796(赠送源码数据库)JAVA、PHP,node.js,C++、python,大屏数据可视化等

node.js旅游景点分享网站 摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。旅游景点分享网站设计&#xff0c;主要的模块包括查看后台首页、轮播图&#xff08;轮播图管理&#xff09;、网站公告…

list-watch和节点亲和性和node亲和性

k8s的集群调度 scheduler:负责调度资源&#xff0c;把pod调度到node节点 预算策略 优先策略 1、list-watch k8s集群当中&#xff0c;通过list-watch的机制进行每个组件的协作&#xff0c;保持数据同步&#xff0c;每个组件之间解耦 kubectl配置文件&#xff0c;向APIserv…

城堡世界定制

城堡世界是一款移动应用程序&#xff0c;通常在手机上使用。 该游戏的主要功能丰富多样&#xff0c;用户可以通过购买不同的城堡卡来开启自己的城堡&#xff0c;这不仅可以满足玩家对个性化的追求&#xff0c;还可以让玩家在游戏中获得更多的乐趣。 作为一家专注于互联网领域的…

Linux进程通信——system V进程间通信

目录 system V共享内存 共享内存的原理 共享内存的建立与释放 共享内存的创建 shmget 共享内存的释放 shmctl 共享内存的关联 shmat 共享内存的去关联 shmdt 用共享内存实现serve和client的简单通信 共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的…

分治法:分而治之

排序算法中的快速排序&#xff0c;归并排序都用了分治思想 题目描述&#xff1a; 题目地址&#xff1a;LeetCode 50 数组中的第K个最大元素 题目描述&#xff1a; 题目地址&#xff1a;LeetCode 215

基于ssm的高校智能培训管理系统分析与设计论文

摘 要 如今的年代&#xff0c;已经是步入信息社会了&#xff0c;不仅信息更新速度频繁&#xff0c;信息量也大&#xff0c;在信息时代必须有相应的处理信息的方法&#xff0c;如果还采用以前的结绳记事或者笔写纸记&#xff0c;不仅是信息录入效率上赶不上节奏&#xff0c;在信…

Superset二次开发之提高Charts下载图片分辨率

需求:图片变高清 现状:Charts下载图片功能,下载的图片分辨率太差,用户体验不友好 源码分析 路径1:superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx接口1:DOWNLOAD_AS_IMAGE路径2:superset-frontend/src/utils/downloadAsImage.ts接口2:d…

VmWare虚拟机的安装

VmWare官方最新版下载地址 vmware官方下载地址 安装流程 安装成功验证 安装完成之后&#xff0c;打开网络中心&#xff0c;一定要确认这里多出两个网络连接&#xff0c;才证明Vmware已经安装成功

静态网页设计——千姿百色旅游网(HTML+CSS+JavaScript)(dw、sublime Text、webstorm、HBuilder X)

前言 声明&#xff1a;该文章只是做技术分享&#xff0c;若侵权请联系我删除。&#xff01;&#xff01; 感谢大佬的视频&#xff1a; https://www.bilibili.com/video/BV1oe411m7kH/?vd_source5f425e0074a7f92921f53ab87712357b 源码&#xff1a;https://space.bilibili.co…