写点什么

鸿蒙 NEXT 开发 - 应用数据持久化之关系型数据库

作者:东林知识库
  • 2025-03-31
    江苏
  • 本文字数:4628 字

    阅读完需:约 15 分钟

1. 应用数据持久化

应用数据持久化,是指应用将内存中的数据通过文件或数据库的形式保存到设备上。内存中的数据形态通常是任意的数据结构或数据对象,存储介质上的数据形态可能是文本、数据库、二进制文件等。


HarmonyOS 标准系统支持典型的存储数据形态,包括用户首选项、键值型数据库、关系型数据库。


  • 用户首选项(Preferences):通常用于保存应用的配置信息。数据通过文本的形式保存在设备中,应用使用过程中会将文本中的数据全量加载到内存中,所以访问速度快、效率高,但不适合需要存储大量数据的场景。

  • 键值型数据库(KV-Store):一种非关系型数据库,其数据以“键值”对的形式进行组织、索引和存储,其中“键”作为唯一标识符。适合很少数据关系和业务关系的业务数据存储,同时因其在分布式场景中降低了解决数据库版本兼容问题的复杂度,和数据同步过程中冲突解决的复杂度而被广泛使用。相比于关系型数据库,更容易做到跨设备跨版本兼容。

  • 关系型数据库(RelationalStore):一种关系型数据库,以行和列的形式存储数据,广泛用于应用中的关系型数据的处理,包括一系列的增、删、改、查等接口,开发者也可以运行自己定义的 SQL 语句来满足复杂业务场景的需要。


2. 应用数据持久化-关系型数据库

2.1 概述

关系型数据库基于 SQLite 组件,适用于存储包含复杂关系数据的场景,比如一个班级的学生信息,需要包括姓名、学号、各科成绩等,又或者公司的雇员信息,需要包括姓名、工号、职位等,由于数据之间有较强的对应关系,复杂程度比键值型数据更高,此时需要使用关系型数据库来持久化保存数据。

2.2 运行机制

关系型数据库对应用提供通用的操作接口,底层使用 SQLite 作为持久化存储引擎,支持 SQLite 具有的数据库特性,包括但不限于事务、索引、视图、触发器、外键、参数化查询和预编译 SQL 语句。


2.3 约束限制

  • 系统默认日志方式是 WAL(Write Ahead Log)模式,系统默认落盘方式是 FULL 模式。

  • 数据库中有 4 个读连接和 1 个写连接,线程获取到空闲读连接时,即可进行读取操作。当没有空闲读连接且有空闲写连接时,会将写连接当做读连接来使用。

  • 为保证数据的准确性,数据库同一时间只能支持一个写操作。

  • 当应用被卸载完成后,设备上的相关数据库文件及临时文件会被自动清除。

  • ArkTS 侧支持的基本数据类型:number、string、二进制类型数据、boolean。

  • 为保证插入并读取数据成功,建议一条数据不要超过 2M。超出该大小,插入成功,读取失败

2.4 常用方法

2.4.1 在生命周期函数中添加代码


导入模块代码


import { relationalStore } from '@kit.ArkData';
复制代码


在 onWindowStageCreate 生命周期函数中添加代码,初始化数据库


// 创建数据库const STORE_CONFIG: relationalStore.StoreConfig = {  name: 'RdbTest.db', // 数据库文件名  securityLevel: relationalStore.SecurityLevel.S3, // 数据库安全级别  encrypt: false, // 可选参数,指定数据库是否加密,默认不加密  customDir: 'customDir/subCustomDir', // 可选参数,数据库自定义路径。数据库将在如下的目录结构中被创建:context.databaseDir + '/rdb/' + customDir,其中context.databaseDir是应用沙箱对应的路径,'/rdb/'表示创建的是关系型数据库,customDir表示自定义的路径。当此参数不填时,默认在本应用沙箱目录下创建RdbStore实例。  isReadOnly: false // 可选参数,指定数据库是否以只读方式打开。该参数默认为false,表示数据库可读可写。该参数为true时,只允许从数据库读取数据,不允许对数据库进行写操作,否则会返回错误码801。};relationalStore.getRdbStore(this.context, STORE_CONFIG, (err, store) => {  if (err) {    console.error(`Failed to get RdbStore. Code:${err.code}, message:${err.message}`);    return;  }  console.info(`Succeeded in getting RdbStore.`);  //保存store, 方便后面我们对数据库的操作  RdbUtil.setStore(store)
})
复制代码


2.4.2 创建实体类 Student

查询的时候需要用实体类接收下数据库里面数据



export default class Student {  id: number = 0  username: string  age: number = 0
constructor(id: number, username: string, age: number) { this.id = id this.username = username this.age = age }}
复制代码

2.4.3 创建工具类 RdbUtil


import relationalStore from '@ohos.data.relationalStore';import Student from '../models/Student';import { BusinessError } from '@ohos.base';
/** * 关系型数据库工具类 */export default class RdbUtil { /** * 数据库对象 */ private static rdbStore: relationalStore.RdbStore;
static setStore(store: relationalStore.RdbStore) { RdbUtil.rdbStore = store; }
static getStore(): relationalStore.RdbStore { return RdbUtil.rdbStore; }
/** * 执行sql * @param sql * @returns */ static executeSql(sql: string): Promise<void> { return RdbUtil.getStore().executeSql(sql); }
/** * 插入数据 * @param tableName * @param data * @returns */ static insert(tableName: string, data: relationalStore.ValuesBucket): Promise<number> { return RdbUtil.getStore().insert(tableName, data); }
/** * 查询数据 * @returns */ static queryAll(): Promise<Array<Student>> { let predicates = new relationalStore.RdbPredicates('STUDENT'); return new Promise<Array<Student>>((resolve, reject) => { RdbUtil.getStore().query(predicates).then((result) => { let students = new Array<Student>(); while (result.goToNextRow()) { let student = new Student( result.getLong(0), result.getString(1), result.getLong(2), ); students.push(student); } resolve(students); }).catch((error: BusinessError) => { reject(error) }) }) }
/** * 删除 * @param id * @returns */ static deleteById(id: number) { let predicates = new relationalStore.RdbPredicates('STUDENT'); predicates.equalTo('ID', id) return RdbUtil.getStore().delete(predicates); }
/** * 更新 * @param id * @param data * @returns */ static updateById(id: number, data: relationalStore.ValuesBucket) { let predicates = new relationalStore.RdbPredicates('STUDENT'); predicates.equalTo('ID', id) return RdbUtil.getStore().update(data, predicates); }}
复制代码


注意:该工具类里面包含了创建表,新增数据,查询数据,更新数据,删除数据 的 api

2.4.4 在界面中操作数据库

import RdbUtil from '../utils/RdbUtil';import { BusinessError } from '@kit.BasicServicesKit';import { promptAction } from '@kit.ArkUI';import { relationalStore } from '@kit.ArkData';import Student from '../models/Student';
@Entry @Component struct Index { build() { Column() { Button('创建数据库表') .onClick(() => { const SQL_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS STUDENT (ID INTEGER PRIMARY KEY AUTOINCREMENT, USERNAME TEXT NOT NULL, AGE INTEGER)'; // 建表Sql语句 RdbUtil.executeSql(SQL_CREATE_TABLE) .then(() => { promptAction.showToast({ message: 'success create table' }) }).catch((err: BusinessError) => { promptAction.showToast({ message: 'fail create table' }) }) }).margin({ bottom: 50 })
Button('插入数据') .onClick(() => { const valueBucket: relationalStore.ValuesBucket = { 'USERNAME': '东林', 'AGE': 18 }; RdbUtil.insert('STUDENT', valueBucket) .then((updateNumber) => { promptAction.showToast({ message: 'insert data success ' + updateNumber }) }).catch((error: BusinessError) => { promptAction.showToast({ message: 'insert data fail ' + error }) }) }).margin({ bottom: 50 })
Button('查询数据') .onClick(() => { RdbUtil.queryAll() .then((students: Array<Student>) => { promptAction.showToast({ message: 'query students success ' + JSON.stringify(students) }) }).catch((error: BusinessError) => { promptAction.showToast({ message: ' query students fail ' + error }) }) }).margin({ bottom: 50 })
Button('修改数据') .onClick(() => { const valueBucket: relationalStore.ValuesBucket = { 'USERNAME': '小红', 'AGE': 20 }; RdbUtil.updateById(1, valueBucket) .then((updateNumber) => { promptAction.showToast({ message: 'update student success ' + updateNumber.toString() }) }).catch((err: BusinessError) => { promptAction.showToast({ message: ' update student fail ' + err }) }) }).margin({ bottom: 50 })

Button('删除数据') .onClick(() => { RdbUtil.deleteById(1) .then((updateNumber) => { promptAction.showToast({ message: 'delete student success ' + updateNumber.toString() }) }).catch((err: BusinessError) => { promptAction.showToast({ message: 'delete student fail ' + err }) }) })
} .height('100%') .width('100%') } }
复制代码

2.4.5 删除数据库

在生命周期函数里面删除数据库




onDestroy(): void {  hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');  // 删除数据库  relationalStore.deleteRdbStore(this.context, 'RdbTest.db', (err) => {    if (err) {      console.error(`Failed to delete RdbStore. Code:${err.code}, message:${err.message}`);      return;    }    console.info('Succeeded in deleting RdbStore.');  });}
复制代码


发布于: 2 小时前阅读数: 8
用户头像

享受当下,享受生活,享受成长乐趣! 2025-02-26 加入

鸿蒙、Java、大数据

评论

发布
暂无评论
鸿蒙NEXT开发-应用数据持久化之关系型数据库_东林知识库_InfoQ写作社区