此文章内容兼容API12,使用harmony next应用开发
鸿蒙的存储方案,包括 状态存储、用户首选项、键值型/关系型数据库。
| 类型 | 解释 | 评价 |
| :--------- | :-------- | :--------- |
| LocalStorage:页面级UI状态存储 | 页面级别,即用@Entry修饰的父组件声明,@Component修饰的子组件们可共享其缓存 | --|
| AppStorage:应用全局UI状态存储 | 应用级别,全局缓存;一处缓存,全局UI均可取值 | --|
| PersistentStorage:持久化UI状态存储 | 磁盘级别缓存 | app退出再次启动,仍保存选定的结果的场景 |
| Perference:用户首选项| 存储在设备中,app使用时会加载到内存中 | 速度快、效率高、不适合大量存储数据|
| KV-Store:键值型数据库| 非关系型数据库,以键值对形式索引、存储 | 适合分布式场景,适合数据和业务关系少的场景 |
| Relational-Store:关系型数据库| 以行列形式索引、存储,支持SQL语句满足复杂业务场景需要 | 适合复杂关系的场景 |
状态存储
LocalStorage
LocalStorage 是页面级UI状态存储
- APP可以创建多个LocalStorage 实例
- @Entry 修饰的组件树,自动被分配一个LocalStorage 实例,其所有子组件自动获得对该实例的访问权限
- 可通过GetShared 接口,实现跨页面、跨UIAbility实例的共享
- 被分配两个装饰器: @LocalStorageProp @LocalStorageLink ; 实现组件间相互联系
- 子组件调用时,支持指定 LocalStorage
类型 | key | value | 初始化 | 子组件初始化 | change |
---|---|---|---|---|---|
LocalStorageProp | string | 必须指定类型; Object、class、string、number、boolean、enum、list、Map、Set、Date |
必须本地初始化 | 可用于初始化@State、@Link、@Prop、@Provide。 | 其变化不会被同步回 LocalStorage,仅会引起本组件的动态刷新 |
LocalStorageLink | string | 必须指定类型; Object、class、string、number、boolean、enum、list、Map、Set、Date |
必须本地初始化 如果LocalStorage实例中不存在属性,则用该初始值初始化该属性,并存入LocalStorage中 |
可用于初始化@State、@Link、@Prop、@Provide。 | 其变化会被同步回 LocalStorage |
1,简单使用
let storage: LocalStorage = new LocalStorage();
@Entry(storage)
@Component
struct Parent {
...
storage.setOrCreate('PropA', 33);
}
@Component
struct Son{
@LocalStorageLink('PropA') childLinkNumber: number = 1;
}
2,父组件指定LocalStorage 传递给子组件
! 当不需要从父组件初始化变量时,第一个参数需要传递 {}
let storage1: LocalStorage = new LocalStorage();
let storage2: LocalStorage = new LocalStorage();
@Entry(storage1)
@Component
struct Parent {
Son({}, storage2)
}
@Component
struct Son{
@LocalStorageLink('PropA') childLinkNumber: number = 1;
}
3,获取跨页面共享 LocalStorage
@Entry({ routeName: 'xxxPage', storage: LocalStorage.getShared() })
@Component
struct xxxPage{}
getShared接口仅能获取当前Stage通过windowStage.loadContent传入的LocalStorage实例,否则返回undefined。
AppStorage
AppStorage 应用级别,全局缓存;一处缓存,全局UI均可取值
- 和应用进程绑定,在应用启动时创建; 主线程内
- AppStorage 是全局单例
- 持久化数据PersistentStorage和环境变量Environment都是通过AppStorage中转; 需要注意 AppStorage 和 PersistentStorage、Environment 调用顺序
- 被分配两个装饰器: @StorageProp @StorageLink ;
- 若引起更改的变量不算用于UI更新,而是用于消息传递,推荐使用 emitter 方式;不建议使用 @StorageLink的双向同步机制实现事件通知
类型 | key | value | 初始化 | 子组件初始化 | change |
---|---|---|---|---|---|
StorageProp | string | 必须指定类型; Object、class、string、number、boolean、enum、list、Map、Set、Date |
必须本地初始化 | 可用于初始化@State、@Link、@Prop、@Provide。 | 允许本地修改,但其变化不会被同步回 AppStorage ,仅会引起本组件的动态刷新【若状态变量】; AppStorage 的更新会覆盖本地修改 |
StorageLink | string | 必须指定类型; Object、class、string、number、boolean、enum、list、Map、Set、Date |
必须本地初始化 如果LocalStorage实例中不存在属性,则用该初始值初始化该属性,并存入LocalStorage中 |
可用于初始化@State、@Link、@Prop、@Provide。 | 其变化会被同步回 AppStorage |
AppStorage.setOrCreate("PropA",33);
@StorageLink("PropA") a: number = 1;
PersistentStorage
PersistentStorage : 持久化存储选定的AppStorage属性
PersistentStorage将选定的AppStorage属性保留在设备磁盘上
- 允许全部类型,除了 嵌套对象(对象数组,对象的属性是对象等)
- 速度缓慢,要避免持久化大型数据集、经常变化数据集
//设置持久化
PersistentStorage.persistProp('PropA', 33);
//获取属性1
let s = AppStorage.get<number>('PropA');
//获取属性2
@StorageLink('aProp') PropA: number = 0;
首选项 preferences
相当于安卓中的 SharedPreferences
- 可指定实例名称
- 存储形式为键值对,key为string,value 为 number string bool 三种
- 无法保证进程安全,不支持多进程下使用
1,Options 实例化时,配置选项
let options: dataPreferences.Options = {
name: this.PREFERENCE_INIT_KEY //实例名称
}
this.sp = dataPreferences.getPreferencesSync(context, options);
2,数据存储
this.sp.put(key, value)
this.sp.flush()
3,数据读取
return this.sp.getSync(key, defaultNum) as number
4,数据删除
this.sp.deleteSync(key)
this.sp.flush()
5,实例清空
let options: dataPreferences.Options = {
name: this.PREFERENCE_DEF_KEY
};
dataPreferences.deletePreferences(this.context, options, (err: BusinessError) => {})
数据库
KV-Store:键值型数据库
非关系型数据库,以键值对形式索引、存储 | 适合分布式场景,适合数据和业务关系少的场景
1,常用功能
- KVManager: 数据库管理类
- SingleKVStore 数据库,提供查询数据和同步数据的方法
(1)初始化管理类
const kvManagerConfig: distributedKVStore.KVManagerConfig = {
context: mContext,
bundleName: mContext.applicationInfo.name //包名
}
try {
mKvManager = distributedKVStore.createKVManager(kvManagerConfig)
} catch (err) {}
(2)使用管理类,创建并获取数据库实例
const options: distributedKVStore.Options = {
createIfMissing: true, // 当数据库文件不存在时是否创建数据库,默认创建
encrypt: false, // 设置数据库文件是否加密,默认不加密
backup: false, // 设置数据库文件是否备份,默认备份
kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, // 设置要创建的数据库类型,默认为多设备协同数据库
securityLevel: distributedKVStore.SecurityLevel.S2 // 设置数据库安全级别
};
try {
mKvStore = await mKvManager.getKVStore<distributedKVStore.SingleKVStore>(CACHE_KVSTORE_NAME, options)
} catch (err) { }
2,数据存储 【句柄是SingleKVStore 数据库实例】
await mKvStore.put(key, value)
3,数据读取
let value = await mKvStore.get(key)
4,删除
await mKvStore.delete(key)
await mKvStore.deleteBatch(keys) //批量删除
5,删除数据库
await mKvManager.deleteKVStore(mContext.applicationInfo.name, CACHE_KVSTORE_NAME)
Relational-Store:关系型数据库
以行列形式索引、存储,支持SQL语句满足复杂业务场景需要
Relational-Store:关系型数据库 官方文档
1,常用功能
- RdbPredicates : 定义数据库的操作条件
- RdbStore:管理关系数据库方法的接口。
- ResultSet:查询接口之后返回的结果集合。
2,创建或获取数据库
//创建 RdbStore
private readonly STORE_CONFIG: relationalStore.StoreConfig = {
name: 'test.db', //数据库名称
securityLevel: relationalStore.SecurityLevel.S1 //安全等级
};
private readonly TABLE_NAME = 'CREATE TABLE IF NOT EXISTS ' + TABLE_NAME +
' (id INTEGER PRIMARY KEY AUTOINCREMENT, mark INTEGER, data TEXT NOT NULL) ',
this.mRdbStore = await relationalStore.getRdbStore(context, this.STORE_CONFIG)
await this.mRdbStore.executeSql(this.mSqlCreateTable);
3,添加数据
//1 实现 ValuesBucket 数据行
let data: relationalStore.ValuesBucket = {
"column1": this.prop1?? new Uint8Array(),
"column2": this.prop2?? new Uint8Array(),
"column3": this.prop3?? new Uint8Array()
};
//2
await this.mRdbStore.insert(this.mTableName, data) // data: relationalStore.ValuesBucket
3,删除数据
//1 创建查询条件 RdbPredicates
let predicates = new relationalStore.RdbPredicates(this.mTableName);
predicates.equalTo("column1", 'test1');
//2
await this.mRdbStore.delete(predicates) // predicates: relationalStore.RdbPredicates
4,查询数据
//1 创建查询条件 RdbPredicates
let predicates = new relationalStore.RdbPredicates(this.mTableName);
predicates.equalTo("column1", 'test1');
//2 查询
const result: T[] = [];
try {
// columns 表示要查询的列。如果值为空,则查询应用于所有列。
let resultSet: relationalStore.ResultSet = await this.mRdbStore.query(predicates, this.mColumns)
let count: number = resultSet.rowCount;
if (count <= 0 || typeof count === 'string') {
resultSet.close();
return result;
} else {
while (resultSet.goToNextRow()){
//取出查询结果
let tmp: T = await this.handleResult(resultSet);
result.push(tmp);
// resultSet.goToNextRow();
}
resultSet.close();
return result;
}
} catch (e) {
console.debug("TAG_DB", 'query error ' + JSON.stringify(e));
}
//3 处理查询结果
result1 = resultSet.getLong(resultSet.getColumnIndex('column1'));
result2 = resultSet.getString(resultSet.getColumnIndex('column2'));
5,更新数据
//1
const valueBucket: relationalStore.ValuesBucket = await this.generateBucket(t);
let predicates = new relationalStore.RdbPredicates(this._rdbTableInfo.tableName);
predicates.equalTo('id', t.id);
//2
await this.mRdbStore.update(data, predicates)