鸿蒙 数据存储

此文章内容兼容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:键值型数据库

非关系型数据库,以键值对形式索引、存储 | 适合分布式场景,适合数据和业务关系少的场景

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)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容