纯血鸿蒙 - 数据持久化

数据持久化是指把应用运行过程中产生的各种数据,通过一定的方式存储到设备的存储介质中,并且这些数据在应用程序结束运行,设备关机重启等情况后依然能够被保留,方便应用在后续再次运行时能够重新获取并使用这些数据。在鸿蒙应用开发中,持久化数据的方式主要有三种:用户首选项 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')
    }
  })
}
相关推荐
郝晨妤3 小时前
鸿蒙原生应用开发元服务 元服务是什么?和App的关系?(保姆级步骤)
android·ios·华为od·华为·华为云·harmonyos·鸿蒙
Peace*3 小时前
HarmonyOs鸿蒙开发实战(16)=>沉浸式效果第一种方案一窗口全屏布局方案
harmonyos·鸿蒙·鸿蒙系统
howard20056 小时前
鸿蒙实战:页面跳转传参
harmonyos·跳转·router·传参
威哥爱编程14 小时前
异步编程在ArkTS中具体怎么实现?
harmonyos·arkts·harmonyos next
ChinaDragonDreamer17 小时前
HarmonyOS:UIAbility组件间交互(设备内)
开发语言·harmonyos·鸿蒙
jikuaidi6yuan1 天前
鸿蒙系统简介
华为·harmonyos
何遇mirror1 天前
【话题】抓住鸿蒙生态崛起的机遇:挑战与对策
华为·harmonyos
万少1 天前
HarmonyOS Next 浅谈 发布-订阅模式
前端·设计模式·harmonyos
东林知识库1 天前
鸿蒙NEXT开发-用户通知服务的封装和文件下载通知
华为·harmonyos
火柴就是我1 天前
Harmony HMRouter Interceptor 的基本使用
harmonyos