数据持久化(2):RelationalStore关系型数据库(SQLite)操作(14)
在 HarmonyOS 开发中,当应用需要存储结构化、关系复杂的数据(如订单、联系人、消息记录等)时,轻量级的 Preferences 或 KVDB 往往无法满足需求。此时,RelationalStore(关系型数据库) 是最佳选择。它底层基于 SQLite 引擎,提供了一套完整的本地数据库管理机制。
以下是基于最新 API (@kit.ArkData) 的 RelationalStore 完整操作指南:
一、 核心概念与适用场景
- 数据结构:采用关系型表结构,支持完整的 SQL 语法(包括事务、索引、视图、触发器等)。
- 适用场景:存储包含复杂关系的数据,例如包含姓名、学号、各科成绩的学生信息,或公司的雇员信息。
- 数据限制:为保证插入并读取成功,建议单条数据大小不要超过 2M。
二、 核心 API 与基础操作
1. 导入模块与初始化
推荐使用新版 @kit.ArkData 模块(旧版 @ohos.data.rdb 已停止维护)。
import { relationalStore } from '@kit.ArkData';
import { common } from '@kit.AbilityKit';
// 1. 定义数据库配置
const STORE_CONFIG: relationalStore.StoreConfig = {
name: 'my_database.db', // 数据库文件名
securityLevel: relationalStore.SecurityLevel.S1 // 安全级别
};
// 2. 获取 RdbStore 实例(通常在 Ability 或全局工具类中执行)
let rdbStore: relationalStore.RdbStore | undefined = undefined;
rdbStore = await relationalStore.getRdbStore(context, STORE_CONFIG);
2. 创建数据表
通过 executeSql 执行标准的 SQL 建表语句:
const CREATE_TABLE_SQL = 'CREATE TABLE IF NOT EXISTS EMPLOYEE (' +
'employeeId TEXT PRIMARY KEY, ' +
'name TEXT NOT NULL, ' +
'age INTEGER, ' +
'salary REAL NOT NULL)';
await rdbStore.executeSql(CREATE_TABLE_SQL);
3. 增删改查 (CRUD) 实战
- 增加 (Insert):使用
ValuesBucket传递键值对数据,成功返回行 ID。
const valueBucket: relationalStore.ValuesBucket = {
'employeeId': 'E001',
'name': '张三',
'age': 28,
'salary': 15000.0
};
const rowId = await rdbStore.insert('EMPLOYEE', valueBucket);
- 删除 (Delete):使用
RdbPredicates定义删除条件。
const predicates = new relationalStore.RdbPredicates('EMPLOYEE');
predicates.equalTo('employeeId', 'E001'); // 指定删除条件
const deletedRows = await rdbStore.delete(predicates);
- 修改 (Update):结合
ValuesBucket和RdbPredicates。
const valueBucket: relationalStore.ValuesBucket = { 'salary': 18000.0 };
const predicates = new relationalStore.RdbPredicates('EMPLOYEE');
predicates.equalTo('employeeId', 'E001');
const updatedRows = await rdbStore.update(valueBucket, predicates);
- 查询 (Query):返回
ResultSet结果集,需手动遍历并务必关闭。
const predicates = new relationalStore.RdbPredicates('EMPLOYEE');
const resultSet = await rdbStore.query(predicates, ['name', 'salary']);
while (resultSet.goToNextRow()) {
const name = resultSet.getString(resultSet.getColumnIndex('name'));
const salary = resultSet.getDouble(resultSet.getColumnIndex('salary'));
console.info(`员工: ${name}, 薪资: ${salary}`);
}
resultSet.close(); // 【关键】使用完毕后必须关闭结果集
三、 进阶能力:分布式与端云同步
RelationalStore 的一大亮点是支持跨设备/端云的数据同步。
- 设置分布式同步表:通过
setDistributedTables将指定的表标记为支持分布式同步。 - 同步策略:支持自动同步 (
autoSync: true) 和手动同步 (cloudSync)。手动同步可配置SYNC_MODE_TIME_FIRST等模式,决定数据流向。 - 数据变化订阅:通过
on("dataChange")监听云端或其他设备的数据变更,结合cursor机制精准拉取增量数据。
四、 开发约束与避坑指南
- 并发写入限制:为保证数据准确性,数据库同一时间只能支持一个写操作(系统默认有 4 个读连接和 1 个写连接)。
- 线程限制:RelationalStore 不支持在 Worker 线程中直接使用,必须在主线程或 TaskPool 中通过特定方式调用。
- 事务处理:对于批量插入或高并发写入场景,强烈建议使用事务 (Transaction) 包裹操作。实测表明,使用事务的性能比非事务高出约 200 倍。
- 生命周期清理:当应用被卸载后,设备上的相关数据库文件及临时文件会被系统自动清除。
五、 深度扩展
在掌握了 RelationalStore 的基础 CRUD 操作后,为了应对真实商业项目的复杂需求,我们需要在性能优化、架构设计、高级特性三个维度进行深度扩展。以下是鸿蒙关系型数据库的进阶实战指南:
1、 性能优化:事务与批量操作
在需要大量写入数据的场景(如首次安装应用拉取离线数据、导入导出报表)中,逐条插入会导致严重的性能瓶颈。
1.1、 批量插入 (batchInsert)
使用 batchInsert 接口可以一次性插入多条数据,大幅减少系统调用开销。
let valuesList: relationalStore.ValuesBucket[] = [];
for (let i = 0; i < 1000; i++) {
valuesList.push({ 'name': `User_${i}`, 'age': 20 + (i % 10) });
}
// 返回实际成功插入的行数
let count = await rdbStore.batchInsert('EMPLOYEE', valuesList);
1.2、 事务管理 (Transaction)
对于涉及多表更新或必须保证原子性的操作,应使用事务。事务能确保操作要么全部成功,要么全部回滚,避免产生脏数据。
let transaction = await rdbStore.createTransaction({});
try {
await transaction.execute(`INSERT INTO EMPLOYEE (name, age) VALUES ('Alice', 25)`);
await transaction.execute(`UPDATE EMPLOYEE SET age = 26 WHERE name = 'Bob'`);
await transaction.commit(); // 提交事务
} catch (err) {
await transaction.rollback(); // 发生异常时回滚
}
2、 架构设计:通用数据库管理类封装
为了避免在业务代码中散落大量的数据库操作逻辑,建议封装一个通用的 RdbManager 工具类,统一管理数据库的初始化、版本升级和 CRUD 操作。
核心设计思路:
- 单例模式:确保全局只有一个数据库连接实例。
- 版本控制:通过
PRAGMA user_version追踪数据库版本,在onUpgrade回调中执行表结构的平滑升级(如新增字段、新建表)。 - 统一异常处理:封装内部
try-catch,对外暴露清晰的 Promise 接口。
// 简化的通用管理类示例
export class RdbManager {
private rdbStore: relationalStore.RdbStore | undefined = undefined;
async initDatabase(context: common.UIAbilityContext) {
const config: relationalStore.StoreConfig = { name: 'app.db', securityLevel: relationalStore.SecurityLevel.S1 };
this.rdbStore = await relationalStore.getRdbStore(context, config);
// 在此处执行建表或版本升级逻辑
}
async insert(table: string, values: relationalStore.ValuesBucket): Promise<number> {
if (!this.rdbStore) throw new Error('DB not initialized');
return await this.rdbStore.insert(table, values);
}
}
3、 高级特性:全文检索 (FTS)
对于聊天消息、文章列表等需要关键字搜索的场景,传统的 LIKE '%keyword%' 查询效率极低。RelationalStore 内置了 FTS (Full-Text Search) 引擎,支持中文 ICU 分词器。
3.1、 创建全文检索虚拟表
const SQL_CREATE_TABLE = 'CREATE VIRTUAL TABLE IF NOT EXISTS articles USING fts4(title, content, tokenize=icu zh_CN)';
await rdbStore.executeSql(SQL_CREATE_TABLE);
3.2、 执行全文检索
使用 MATCH 语法进行高效查询:
let predicates = new relationalStore.RdbPredicates('articles');
predicates.match('content', '鸿蒙开发'); // 搜索包含“鸿蒙开发”的文章
let resultSet = await rdbStore.query(predicates, ['title', 'content']);
4、 分布式与端云数据同步机制
RelationalStore 提供了强大的分布式能力,支持设备间、端云间的数据无缝流转。
4.1、 设置分布式表
通过 setDistributedTables 将需要同步的表标记为分布式表,并配置 autoSync: true 开启自动同步。
let config: relationalStore.DistributedConfig = { autoSync: true };
rdbStore.setDistributedTables(['EMPLOYEE'], relationalStore.DistributedType.DISTRIBUTED_CLOUD, config);
4.2、 增量数据感知 (Cursor 机制)
在端云同步场景中,如何知道哪些数据是最新变化的?系统为每行数据绑定了 cursor 字段。每次增删改操作,该字段都会递增。
- 应用只需记录上次的最大
cursor值。 - 使用
predicates.greaterThan(relationalStore.Field.CURSOR_FIELD, lastCursor)即可精准拉取增量数据。
4.3、 订阅数据变化
通过 on("dataChange") 监听云端或其他组网设备的数据变更,一旦收到通知,立即触发增量拉取并刷新本地 UI。
5、 进阶避坑与约束
- 动态库加载限制:如果使用了自定义分词器扩展(如通过
pluginLibs加载.so文件),需注意动态库数量最多为 16个,且必须包含全部依赖,否则会导致开库失败(错误码 14800000/14800010)。 - 脏数据处理:在端云同步中,如果开库时将
autoCleanDirtyData设为false,云端删除数据时不会自动删除本地数据。此时必须通过cursor查出被标记删除的数据,并手动调用cleanDirtyData方法进行清理。 - Returning 子句约束:在执行带有
returning关键字的 SQL 操作时,指定返回的字段名不能包含空格、逗号及星号,且最多支持返回 1 到 4 个字段。
更多推荐


所有评论(0)