进阶:数据存储

Preferences,KV-Store和SQLite

type
status
date
slug
summary
tags
category
icon
password

概述

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

一、用户首选项

用户首选项Preferences,类似于Android中的SharedPreferences,为应用提供Key-Value键值型的数据存储能力,常用于轻量级的数据存储,如应用配置。进程中每个文件对应一个Preferences实例,应用获取到实例后,可以从中读取数据,或者将数据存入实例中。通过调用flush方法可以将实例中的数据回写到文件里。
notion image

1.1 首选项与非关系数据库的对比

分类
关系型数据库
用户首选项
数据库类型
关系型
非关系型,不保证遵循ACID(Atomicity, Consistency, Isolation and Durability)特性,数据之间无关系
使用场景
提供复杂场景下的本地数据库管理机制
对Key-Value结构的数据进行存取和持久化操作
存储方式
SQLite数据库
文件
约束与限制
1.连接池最大4个 2.同一时间只支持一个写操作
1.建议数据不超一万条 2.Key为string型

1.2 接口说明

以下是用户首选项持久化功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见用户首选项
接口名称
描述
getPreferences(context: Context, name: string, callback: AsyncCallback<Preferences>): void
获取Preferences实例。
put(key: string, value: ValueType, callback: AsyncCallback<void>): void
将数据写入Preferences实例,可通过flush将Preferences实例持久化。
has(key: string, callback: AsyncCallback<boolean>): void
检查Preferences实例是否包含名为给定Key的存储键值对。给定的Key值不能为空。
get(key: string, defValue: ValueType, callback: AsyncCallback<ValueType>): void
获取键对应的值,如果值为null或者非默认值类型,返回默认数据defValue。
delete(key: string, callback: AsyncCallback<void>): void
从Preferences实例中删除名为给定Key的存储键值对。
flush(callback: AsyncCallback<void>): void
将当前Preferences实例的数据异步存储到用户首选项持久化文件中。
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
从内存中移除指定的Preferences实例。若Preferences实例有对应的持久化文件,则同时删除其持久化文件。

1.3 示例

二、键值型数据库

2.1 场景介绍

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

2.2 约束限制

  • 设备协同数据库,针对每条记录,Key的长度≤896 Byte,Value的长度<4 MB。
  • 单版本数据库,针对每条记录,Key的长度≤1 KB,Value的长度<4 MB。
  • 每个应用程序最多支持同时打开16个键值型分布式数据库。
  • 键值型数据库事件回调方法中不允许进行阻塞操作,例如修改UI组件。

2.3 接口说明

以下是键值型数据库持久化功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见分布式键值数据库
接口名称
描述
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|boolean|number>): void
获取指定键的值。
delete(key: string, callback: AsyncCallback<void>): void
从数据库中删除指定键值的数据。

2.3 示例

三、关系型数据库

3.1 场景介绍

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

3.2 基本概念

  • 谓词:数据库中用来代表数据实体的性质、特征或者数据实体之间关系的词项,主要用来定义数据库的操作条件。
  • 结果集:指用户查询之后的结果集合,可以对数据进行访问。结果集提供了灵活的数据访问方式,可以更方便地拿到用户想要的数据。

3.3 运作机制

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

3.4 约束限制

  • 系统默认日志方式是WAL(Write Ahead Log)模式,系统默认落盘方式是FULL模式。
  • 数据库中连接池的最大数量是4个,用以管理用户的读操作。
  • 为保证数据的准确性,数据库同一时间只能支持一个写操作。
  • 当应用被卸载完成后,设备上的相关数据库文件及临时文件会被自动清除。

3.5 接口说明

以下是关系型数据库持久化功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见关系型数据库
接口名称
描述
getRdbStore(context: Context, config: StoreConfig, callback: AsyncCallback<RdbStore>): void
获得一个相关的RdbStore,操作关系型数据库,用户可以根据自己的需求配置RdbStore的参数,然后通过RdbStore调用相关接口可以执行相关的数据操作。
executeSql(sql: string, bindArgs: Array<ValueType>, callback: AsyncCallback<void>):void
执行包含指定参数但不返回值的SQL语句。
insert(table: string, values: ValuesBucket, callback: AsyncCallback<number>):void
向目标表中插入一行数据。
update(values: ValuesBucket, predicates: RdbPredicates, callback: AsyncCallback<number>):void
根据RdbPredicates的指定实例对象更新数据库中的数据。
delete(predicates: RdbPredicates, callback: AsyncCallback<number>):void
根据RdbPredicates的指定实例对象从数据库中删除数据。
query(predicates: RdbPredicates, columns: Array<string>, callback: AsyncCallback<ResultSet>):void
根据指定条件查询数据库中的数据。
deleteRdbStore(context: Context, name: string, callback: AsyncCallback<void>): void
删除数据库。

3.6 示例

附:参考链接