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