纯血鸿蒙 - 数据持久化

数据持久化是指把应用运行过程中产生的各种数据,通过一定的方式存储到设备的存储介质中,并且这些数据在应用程序结束运行,设备关机重启等情况后依然能够被保留,方便应用在后续再次运行时能够重新获取并使用这些数据。在鸿蒙应用开发中,持久化数据的方式主要有三种:用户首选项 Preferences,键值型数据库和关系型数据库。

Preferences

Preferences 是一种轻量级的数据存储方式,用于存储和读取简单的键值对数据,类似于 Android 开发中的 SharedPreferences,可以将数据缓存在内存中,也可以通过 flush 接口将数据写入持久化文件中。

获取 Preferences 实例

ts 复制代码
export let myPreferences: preferences.Preferences | null = null

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    let options: preferences.Options = {
      name: 'myPreferences'
    }
    myPreferences = preferences.getPreferencesSync(this.context, options)
    // ......
  }

  // ......
}

读写数据

ts 复制代码
myPreferences?.putSync('name', 'huawei')
const myPreferencesData = myPreferences?.getSync('name', 'default value')

也可以使用异步方法

ts 复制代码
myPreferences?.put('name', 'huawei', (error: BusinessError) => {
  if (error) {
    console.error('put data error: ' + error.message)
  } else {
    const myPreferencesData = myPreferences?.getSync('name', 'default value')
  }
})

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

值支持的数据类型

ts 复制代码
type ValueType = number | string | boolean | Array<number> | Array<string> | Array<boolean> | Uint8Array | object | bigint

判断 Preferences 实例是否包含指定 Key 的键值对

ts 复制代码
const hasSync = myPreferences?.hasSync('name')

删除数据

ts 复制代码
myPreferences?.delete('name')

flush 实现数据持久化

ts 复制代码
myPreferences?.flush((error: BusinessError) => {
  if (error) {
    console.error('flush error: ' + error.message)
  } else {
    console.info('flush success')
  }
})

监听数据变化

ts 复制代码
myPreferences?.on('change', (key: string) => {
  //todo
})

清空所有数据

ts 复制代码
myPreferences?.clearSync()

键值型数据库

Preferences 主要存储一些简单的键值对数据,如配置信息,应用设置等。与之不同的是,键值对数据库适合存储大量和复杂的数据。

获取键值型数据库

ts 复制代码
export let kvManager: distributedKVStore.KVManager | undefined = undefined

export let kvStore: distributedKVStore.SingleKVStore | undefined = undefined

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    const kvManagerConfig: distributedKVStore.KVManagerConfig = {
      context: this.context,
      bundleName: 'com.example.myapplication'
    }
    try {
      kvManager = distributedKVStore.createKVManager(kvManagerConfig)
      const options: distributedKVStore.Options = {
        createIfMissing: true, //在数据库文件不存在时是否创建数据库
        encrypt: false, //是否要加密数据库文件
        backup: false, //是否备份数据库文件
        autoSync: false, //数据库文件是否自动同步
        kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, //数据库类型:设备协同数据库/单版本数据库
        securityLevel: distributedKVStore.SecurityLevel.S1 //数据库安全等级
      }
      kvManager.getKVStore<distributedKVStore.SingleKVStore>('userInfo', options,
        (err, store: distributedKVStore.SingleKVStore) => {
          if (err) {
            console.error(`getKVStore error message: ${err.message}`)
          } else {
            console.info('getKVStore success')
            kvStore = store
          }
        })
    } catch (e) {
      let error = e as BusinessError
      console.error('catch error message: ' + error.message)
    }
    if (kvStore !== undefined) {
      kvStore = kvStore as distributedKVStore.SingleKVStore
    }
  }

  //......
}

插入数据,当 Key 存在时,put 会修改其值,否则新增一条数据。

ts 复制代码
try {
  kvStore?.put('name', "huawei", (err) => {
    if (err) {
      console.error('put data error message: ' + err.message)
    } else {
      console.info('put data success')
    }
  })
} catch (e) {
  let error = e as BusinessError
  console.error('put data catch error message: ' + error.message)
}

获取对应键的值

ts 复制代码
try {
  kvStore?.get('name', (err, data) => {
    if (err) {
      console.error('get data error message: ' + err.message)
    } else {
      console.info('get data success: ' + data)
    }
  })
} catch (e) {
  let error = e as BusinessError
  console.error('get data catch error message: ' + error.message)
}

删除对应键的数据

ts 复制代码
try {
  kvStore?.delete('name', (err) => {
    if (err) {
      console.error('delete data error message: ' + err.message)
    } else {
      console.info('delete data success')
    }
  })
} catch (e) {
  let error = e as BusinessError
  console.error('delete data catch error message: ' + error.message)
}

删库

ts 复制代码
try {
  kvStore = undefined
  kvManager?.deleteKVStore('com.example.myapplication', 'KVStoreId', (err: BusinessError) => {
    if (err) {
      console.error('deleteKVStore error message: ' + err.message)
    } else {
      console.info('deleteKVStore success')
    }
  })
} catch (e) {
  let error = e as BusinessError
  console.error('deleteKVStore catch error message: ' + error.message)
}

关系型数据库

关系型数据库基于 SQLite,适用于存储复杂关系数据的场景。

创建数据库

ts 复制代码
export let dbStore: relationalStore.RdbStore | undefined = undefined

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    const STORE_CONFIG: relationalStore.StoreConfig = {
      name: 'MySqlite.db', //数据库文件名
      securityLevel: relationalStore.SecurityLevel.S3, //数据库安全级别
      encrypt: false, //数据库是否加密,默认不加密
    }
    relationalStore.getRdbStore(this.context, STORE_CONFIG, (err, store) => {
      if (err) {
        console.error("getRdbStore error message: " + err.message)
      } else {
        // 当数据库创建时,数据库默认版本为0
        if (store.version === 0) {
          //建表
          store.executeSql('create table if not exists user (id integer primary key autoincrement, name text not null, phone text)')
          // 设置数据库版本,须大于0
          store.version = 1
        }
        dbStore = store
      }

    });
    //......
  }

  //......
}

插入数据

ts 复制代码
const valueBucket: relationalStore.ValuesBucket = {
  name: 'Jack',
  phone: '88888888'
}
if (dbStore) {
  (dbStore as relationalStore.RdbStore).insert('user', valueBucket, (error, row) => {
    if (error) {
      console.error('insert fail message: ' + error.message)
    } else {
      console.info('insert success row: ' + row)
    }
  })
}

删除数据

ts 复制代码
const predicates = new relationalStore.RdbPredicates('user')
predicates.equalTo('name', 'Jack')
if (dbStore) {
  (dbStore as relationalStore.RdbStore).delete(predicates, (error, row) => {
    if (error) {
      console.error('delete fail message: ' + error.message)
    } else {
      console.info('delete success row: ' + row)
    }
  })
}

修改数据

ts 复制代码
const valueBucket: relationalStore.ValuesBucket = {
  name: 'Jack',
  phone: '123456789'
}
const predicates = new relationalStore.RdbPredicates('user')
predicates.equalTo('name', 'Jack')
if (dbStore) {
  (dbStore as relationalStore.RdbStore).update(valueBucket, predicates, (error, row) => {
    if (error) {
      console.error('update fail message: ' + error.message)
    } else {
      console.info('update success row: ' + row)
    }
  })
}

查询数据

ts 复制代码
const predicates = new relationalStore.RdbPredicates('user')
predicates.equalTo('name', 'Jack')
if (dbStore) {
  (dbStore as relationalStore.RdbStore).query(predicates, ['id', 'name', 'phone'], (error, cursor) => {
    if (error) {
      console.error('query db error message: ' + error.message)
    } else {
      console.info('query db success')
      while (cursor.goToNextRow()) {
        const id = cursor.getLong(cursor.getColumnIndex('id'))
        const name = cursor.getString(cursor.getColumnIndex('name'))
        const phone = cursor.getString(cursor.getColumnIndex('phone'))
      }
      // 释放内存
      cursor.close();
    }
  })
}

数据库版本不一致时,需要进行数据库升级,比如往 user 表中添加一列。

ts 复制代码
const STORE_CONFIG: relationalStore.StoreConfig = {
  name: 'MySqlite.db',
  securityLevel: relationalStore.SecurityLevel.S3,
  encrypt: false,
}
relationalStore.getRdbStore(this.context, STORE_CONFIG, (err, store) => {
  if (err) {
    console.error("getRdbStore error message: " + err.message)
  } else {
    if (store.version === 0) {
      store.executeSql('create table if not exists user (id integer primary key autoincrement, name text not null, phone text)')
      store.version = 1
    }
    dbStore = store
    //数据库升级
    if (store.version === 1) {
      store.executeSql('alter table user add column address text')
      store.version = 2
    }
  }
})

删除数据库

ts 复制代码
relationalStore.deleteRdbStore(getContext(this), 'MySqlite.db', (error: BusinessError) => {
  if (error) {
    console.error('delete MySqlite error message: ' + error.message)
  } else {
    console.info('delete MySqlite success')
  }
})

如果担心数据库被什么意外或误操作删除了,那就得备份一下该数据库了。

ts 复制代码
if (dbStore) {
  (dbStore as relationalStore.RdbStore).backup("MyBackupSqlite.db", (error: BusinessError) => {
    if (error) {
      console.error('backup MySqlite error message: ' + error.message)
    } else {
      console.info('backup MySqlite success')
    }

  })
}

若是真被删了,有备份的话执行恢复即可。

ts 复制代码
if (dbStore) {
  (dbStore as relationalStore.RdbStore).restore("MyBackupSqlite.db", (error: BusinessError) => {
    if (error) {
      console.error('restore MySqlite error message: ' + error.message)
    } else {
      console.info('restore MySqlite success')
    }
  })
}
相关推荐
whysqwhw1 小时前
鸿蒙分布式投屏
harmonyos
whysqwhw2 小时前
鸿蒙AVSession Kit
harmonyos
whysqwhw4 小时前
鸿蒙各种生命周期
harmonyos
whysqwhw5 小时前
鸿蒙音频编码
harmonyos
whysqwhw5 小时前
鸿蒙音频解码
harmonyos
whysqwhw5 小时前
鸿蒙视频解码
harmonyos
whysqwhw5 小时前
鸿蒙视频编码
harmonyos
ajassi20006 小时前
开源 Arkts 鸿蒙应用 开发(十八)通讯--Ble低功耗蓝牙服务器
华为·开源·harmonyos
前端世界7 小时前
在鸿蒙应用中快速接入地图功能:从配置到实战案例全解析
华为·harmonyos
江拥羡橙8 小时前
【基础-判断】HarmonyOS提供了基础的应用加固安全能力,包括混淆、加密和代码签名能力
安全·华为·typescript·harmonyos