HarmonyOS ArkTS 数据持久化实战:Preferences、RDB 与分布式数据对象的选型
一、三种持久化能力各管一段
几乎每个 HarmonyOS 应用都绕不开数据存储:记住用户偏好、缓存列表数据、保存业务记录。ArkTS 提供了三层持久化能力:Preferences 轻量键值存储、关系型数据库 RDB、以及面向多设备的分布式数据对象。选错层级,要么性能浪费,要么功能不够用。
二、Preferences:小而高频的数据
Preferences 适合存储访问频繁、体积很小的键值对,例如主题设置、开关状态、上次浏览位置。它整体加载进内存,读写是内存操作,因此极快;相应地,数据量大时内存占用会成为问题。
import { preferences } from '@kit.ArkData';
async function saveTheme(mode: string): Promise<void> {
const store = await preferences.getPreferences(getContext(), 'app_setting');
await store.put('theme_mode', mode);
await store.flush();
}
两个细节值得注意:
put之后必须调用flush,否则进程退出时内存中的修改可能未落盘;- 单条键值建议控制在 KB 级别,把一张 JSON 化的大表塞进一个 key,等于绕开了所有键值存储的优化。
三、RDB:结构化数据的正选
一旦数据出现“多行多列、需要条件查询、需要事务”的特征,就应该使用关系型数据库。RDB 底层是 SQLite,通过谓词封装了查询构造,避免手写 SQL 字符串拼接。
import { relationalStore } from '@kit.ArkData';
const config: relationalStore.RdbStoreConfig = {
name: 'record.db',
securityLevel: relationalStore.SecurityLevel.S1
};
async function queryUnfinished(db: relationalStore.RdbStore): Promise<number> {
const predicates = new relationalStore.RdbPredicates('task');
predicates.equalTo('done', 0);
const result = await db.query(predicates, ['id']);
const count = result.rowCount;
result.close();
return count;
}
实践中容易出问题的三个地方:
- 忘记关闭 ResultSet。 查询结果持有底层游标,不调用
close()会造成句柄泄漏,长期运行后出现查询失败。 - 主线程执行重查询。 全表扫描、模糊匹配、大批量写入都应放入 TaskPool,否则列表页滚动会掉帧。
- 升级脚本不幂等。 版本升级时的建表、加列逻辑要写成“存在则跳过”,否则老用户升级会崩在数据库初始化。
四、分布式数据:跨设备才需要
分布式数据对象适合“同一份数据在多台设备上实时可见”的场景,例如手机上编辑、平板上继续看。它的同步由系统负责,开发者只需标注数据并处理变更回调。如果没有多端协同需求,引入它只会增加复杂度。
五、一张选型表
| 数据特征 | 推荐方案 | 典型例子 |
|---|---|---|
| 几个开关、一段配置 | Preferences | 深色模式、免打扰开关 |
| 多行记录、条件查询 | RDB | 待办清单、聊天记录 |
| 结构化但体量小、整体读写 | Preferences 存 JSON | 最近搜索词列表 |
| 多设备实时同步 | 分布式数据对象 | 跨端续写的笔记草稿 |
六、加密与安全
持久化数据的安全等级通过 securityLevel 声明,从 S1 到 S4 逐级增强。含个人信息的业务库建议至少 S2,金融类数据使用 S3 及以上。同时避免把明文口令、令牌直接入库,优先使用系统提供的凭据管理能力。
七、小结
持久化选型遵循“层级匹配”原则:键值偏好交给 Preferences,结构化业务交给 RDB,跨端协同交给分布式数据对象。在这个基础上,把 flush、close、事务、主线程隔离这些工程细节做到位,数据层就能长期稳定运行,而不是每隔几个版本修一次数据丢失问题。
- 点赞
- 收藏
- 关注作者
评论(0)