OpenHarmony 关系型数据库 RDB 完整封装(API Version23 本地持久化数据库)

发布时间:2026/11/5 11:43:44

OpenHarmony 关系型数据库 RDB 完整封装(API Version23 本地持久化数据库) 摘要RDB 是鸿蒙内置轻量关系型数据库基于 SQLite 封装适合存储结构化大量数据笔记、用户列表、商品数据相比 Preferences 仅适合简单键值对RDB 支持表、字段、主键、条件分页查询、多条件筛选、批量增删改查。API23 重构数据库实例生命周期、事务、字段类型校验、并发锁机制修复旧版数据库未关闭导致占用、大量数据查询卡顿、事务回滚失效、多页面同时操作崩溃等问题。本文封装通用 RDB 工具基类附带笔记业务数据表完整 CRUD、分页查询、事务批量插入实战代码给出数据库初始化、资源释放、事务使用规范适配所有需要本地大量结构化存储的项目。关键词OpenHarmonyArkTSAPI23relationalStoreRDB本地数据库SQLite事务分页查询一、引言1.1 RDB 开发背景本地存储分为两类Preferences小型键值存储仅存配置、开关、token不支持复杂查询RDB 关系数据库结构化数据表支持主键、自增、WHERE 条件、分页、批量操作适合笔记、通讯录、本地缓存列表等多条业务数据。API23 RDB 核心升级点强制规范 RdbStore 实例生命周期不用必须 close防止文件锁占用完善事务 transaction 原子操作批量插入失败自动回滚优化 RdbPredicates 条件构造器替代手写拼接 SQL 防注入统一字段类型强校验区分数字、文本、布尔多页面并发读写加内置读写锁避免同时操作数据库崩溃升级大数量查询内存优化分页读取不一次性加载全部数据。1.2 开发环境与场景模块ohos.data.relationalStore 无需额外动态权限应用沙盒自有数据库读写权限 测试场景笔记新增 / 删除 / 修改、分页加载列表、批量插入事务、按标题模糊搜索、清空数据表二、API23 RDB 核心基础 API2.1 数据库初始化配置etsimport relationalStore from ohos.data.relationalStore const storeConfig: relationalStore.StoreConfig { name: app_db, // 数据库文件名 securityLevel: relationalStore.SecurityLevel.S1 // 安全等级 } // 获取数据库实例 const rdbStore await relationalStore.getRdbStore(context, storeConfig)2.2 建表 SQL 示例sqlCREATE TABLE IF NOT EXISTS note ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, content TEXT, create_time INTEGER )2.3 核心操作方法executeSql (sql)执行建表、删除表、自定义 SQLinsert (table, values)新增单条数据update (table, values, predicates)按条件修改delete (table, predicates)按条件删除query (table, columns, predicates)条件查询返回 ResultSetbeginTransaction /commit/rollback事务批量操作close ()关闭数据库释放文件锁2.4 RdbPredicates 条件构造器防 SQL 注入etslet predicates new relationalStore.RdbPredicates(note) predicates.equalTo(id, 1) // id1 predicates.contains(title, 鸿蒙) // 模糊搜索标题 predicates.orderByDesc(create_time) // 按创建时间倒序 predicates.offset(0).limit(10) // 分页2.5 API23 强制约束页面销毁、工具释放必须调用 close ()否则数据库文件持续锁定无法删除复杂查询禁止手写拼接字符串 SQL统一使用 RdbPredicates批量新增、批量删除必须包裹事务避免中途插入一半数据错乱ResultSet 使用完毕必须 close否则内存持续占用禁止全局单例长期持有 RdbStore切换页面重新获取实例。三、通用 RDB 底层工具封装 utils/rdb_util.etsetsimport relationalStore from ohos.data.relationalStore import common from ohos.app.ability.common import promptAction from ohos.promptAction // 笔记实体类型导出 export interface Note { id: number title: string content: string create_time: number } // 数据库配置常量 const DB_NAME note_database const TABLE_NOTE note class RdbUtil { private static instance: RdbUtil private ctx: common.UIAbilityContext | null null private store: relationalStore.RdbStore | null null static getInstance(): RdbUtil { if (!RdbUtil.instance) { RdbUtil.instance new RdbUtil() } return RdbUtil.instance } // 注入页面上下文 setContext(context: common.UIAbilityContext) { this.ctx context } // 初始化数据库自动建表 async init(): Promiseboolean { if (!this.ctx) { promptAction.showToast({ message: 上下文未初始化 }) return false } try { const config: relationalStore.StoreConfig { name: DB_NAME, securityLevel: relationalStore.SecurityLevel.S1 } this.store await relationalStore.getRdbStore(this.ctx, config) // 创建笔记表 const createTableSql CREATE TABLE IF NOT EXISTS ${TABLE_NOTE} ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, content TEXT, create_time INTEGER ) await this.store.executeSql(createTableSql) return true } catch (err) { promptAction.showToast({ message: 数据库初始化失败 }) console.error(rdb init error, err) return false } } // 新增笔记返回自增id async addNote(title: string, content: string): Promisenumber { if (!this.store) return -1 const values: Recordstring, any { title, content, create_time: new Date().getTime() } const rowId await this.store.insert(TABLE_NOTE, values) return rowId } // 根据id删除笔记 async deleteNote(id: number): Promiseboolean { if (!this.store) return false const predicates new relationalStore.RdbPredicates(TABLE_NOTE) predicates.equalTo(id, id) const delCount await this.store.delete(TABLE_NOTE, predicates) return delCount 0 } // 修改笔记 async updateNote(id: number, title: string, content: string): Promiseboolean { if (!this.store) return false const values: Recordstring, any { title, content } const predicates new relationalStore.RdbPredicates(TABLE_NOTE) predicates.equalTo(id, id) const updateCount await this.store.update(TABLE_NOTE, values, predicates) return updateCount 0 } // 分页查询笔记列表时间倒序 async queryNoteList(page: number, pageSize: number, keyword: string ): PromiseNote[] { if (!this.store) return [] const predicates new relationalStore.RdbPredicates(TABLE_NOTE) // 模糊搜索 if (keyword) { predicates.contains(title, keyword) } predicates.orderByDesc(create_time) predicates.offset(page * pageSize).limit(pageSize) const resultSet await this.store.query(TABLE_NOTE, [id, title, content, create_time], predicates) const list: Note[] [] while (resultSet.goToNextRow()) { list.push({ id: resultSet.getLong(0), title: resultSet.getString(1), content: resultSet.getString(2), create_time: resultSet.getLong(3) }) } // 释放结果集 resultSet.close() return list } // 批量插入事务示例 async batchAddNote(noteArr: Array{ title: string, content: string }): Promiseboolean { if (!this.store) return false try { await this.store.beginTransaction() for (const item of noteArr) { await this.store.insert(TABLE_NOTE, { title: item.title, content: item.content, create_time: new Date().getTime() }) } await this.store.commit() return true } catch (err) { await this.store.rollback() console.error(批量插入失败事务回滚, err) return false } } // 清空整张笔记表 async clearAllNote(): Promisevoid { if (!this.store) return const predicates new relationalStore.RdbPredicates(TABLE_NOTE) await this.store.delete(TABLE_NOTE, predicates) } // 关闭数据库释放锁页面销毁必须调用 async closeDB() { if (this.store) { await this.store.close() this.store null } } } export default RdbUtil.getInstance()四、实战页面笔记增删改查分页页面etsimport RdbUtil, { Note } from ../utils/rdb_util import promptAction from ohos.promptAction Entry Component struct RdbNotePage { State noteList: Note[] [] State searchKey: string pageIndex: number 0 readonly PAGE_SIZE 10 async aboutToAppear() { const ctx getContext(this) RdbUtil.setContext(ctx) const initOk await RdbUtil.init() if (initOk) { await this.refreshList() } } // 刷新第一页数据 async refreshList() { this.pageIndex 0 this.noteList await RdbUtil.queryNoteList(this.pageIndex, this.PAGE_SIZE, this.searchKey) } // 加载下一页 async loadMore() { this.pageIndex 1 const more await RdbUtil.queryNoteList(this.pageIndex, this.PAGE_SIZE, this.searchKey) if (more.length 0) { this.noteList [...this.noteList, ...more] } else { promptAction.showToast({ message: 没有更多笔记 }) } } // 新增笔记弹窗简易逻辑 async addNewNote() { const id await RdbUtil.addNote(新建笔记, 这里是笔记内容文本) if (id 0) { promptAction.showToast({ message: 新增成功 }) await this.refreshList() } } // 删除单条笔记 async delItem(id: number) { const res await RdbUtil.deleteNote(id) if (res) { promptAction.showToast({ message: 删除完成 }) await this.refreshList() } } build() { Column({ space: 12 }) { Row({ space: 10 }) { TextInput({ text: this.searchKey, placeholder: 搜索笔记标题 }) .layoutWeight(1) .onChange(val this.searchKey val) Button(搜索).onClick(() this.refreshList()) } .width(95%) Row({ space: 10 }) { Button(新增笔记).backgroundColor(#007DFF).onClick(() this.addNewNote()) Button(加载更多).backgroundColor(#009966).onClick(() this.loadMore()) Button(清空全部).backgroundColor(#f56c6c).onClick(async () { await RdbUtil.clearAllNote() await this.refreshList() }) } List({ space: 10 }).layoutWeight(1).width(95%) { ForEach(this.noteList, (item: Note) { ListItem() { Row() { Column({ space: 4 }).layoutWeight(1) { Text(item.title).fontSize(17).fontWeight(500) Text(item.content).fontColor(#666) } Button(删除).backgroundColor(#f56c6c) .onClick(() this.delItem(item.id)) } .width(100%) .padding(16) .backgroundColor(Color.White) .borderRadius(10) } }) } } .width(100%) .height(100%) .padding(15) .backgroundColor(#F5F5F5) } async aboutToDisappear() { // 页面退出关闭数据库释放文件锁 await RdbUtil.closeDB() } }五、事务批量插入演示页面片段ets// 批量测试数据插入 async function batchInsertDemo() { const data [ { title: 批量笔记1, content: 批量事务测试内容1 }, { title: 批量笔记2, content: 批量事务测试内容2 }, { title: 批量笔记3, content: 批量事务测试内容3 } ] const ok await RdbUtil.batchAddNote(data) if (ok) { promptAction.showToast({ message: 批量插入完成 }) await refreshList() } else { promptAction.showToast({ message: 批量插入失败已回滚 }) } }六、API23 RDB 开发规范6.1 生命周期规范页面aboutToAppear传入上下文并执行 init 初始化页面aboutToDisappear必须调用 closeDB 关闭 RdbStore 释放文件锁ResultSet 查询结果集使用完立即 close避免内存泄漏。6.2 事务使用规范批量新增、批量删除、多表联动修改必须开启事务出现异常执行 rollback 回滚保证原子性不会出现半截数据单条增删改无需事务减少性能开销。6.3 查询性能规范列表统一分页 offsetlimit禁止一次性查询上千条模糊搜索使用 RdbPredicates.contains禁止拼接 SQL 字符串常用查询字段建立索引建表 SQL 增加 INDEX提升检索速度。6.4 安全规范所有条件过滤使用 RdbPredicates杜绝 SQL 注入风险用户输入内容不直接拼接进 executeSql 原始语句。七、高频报错与解决方案问题 1数据库文件被占用无法删除 / 初始化失败 解决页面退出调用 closeDB及时释放 RdbStore 实例。问题 2查询结果为空新增数据不显示 解决确认 init 建表语句执行成功主键自增配置正确。问题 3批量插入一半数据中断数据残留 解决批量操作包裹 beginTransaction commit异常执行 rollback。问题 4页面多次进入数据库卡顿 解决不要全局持有 store每次页面重新初始化退出关闭。问题 5升级 API23 旧版 sql 拼接查询报错 解决全部替换为 RdbPredicates 条件构造器废弃字符串拼接 SQL。问题 6ResultSet 内存持续上涨 解决循环读取完数据后调用 resultSet.close () 释放。八、总结RDB 是鸿蒙本地结构化海量数据存储标准方案API23 完善数据库实例生命周期、事务原子操作、条件安全查询、并发读写锁能力弥补 Preferences 无法复杂查询、仅支持简单键值对的短板。 封装通用 Rdb 工具类统一管理初始化、增删改查、分页搜索、批量事务、资源释放搭配完整笔记业务页面可直接集成进之前 HAR/HSP 分层架构项目适用于课程设计、毕设中笔记、通讯录、本地缓存等结构化数据持久化场景。
延伸阅读

更多相关文章

2026/10/30 8:33:53

为什么同一个问题,AI 每次给出的答案都不一样?

第一次问 AI,它说方案 A 最合适;刷新后再问,它又推荐方案 B。写文案时,这种变化带来灵感;查事实时,却让人心里没底。同一个问题为什么没有唯一答案?是 AI 随机乱说,还是我们其实没有…

2026/11/4 6:34:44

你以为 AI 在思考,其实它只是在猜下一个词?真相没那么简单

“大模型不就是自动补全吗?”这句话既抓住了核心,又很容易把人带偏。它确实通过预测下一个词元来训练和生成,但“训练目标简单”不等于“最终能力简单”。就像钢琴只有有限的琴键,却能演奏完全不同的作品;理解 AI&…

2026/10/23 16:22:00

2026年批发订货小程序哪个好?不同行业批发商该怎么挑

今天给大家带来2026年批发订货小程序哪个好?不同行业批发商该怎么挑。据艾瑞咨询2025年《中国小程序电商行业发展报告》,2025年中国小程序电商交易规模突破4.8万亿元,B2B批发订货类小程序占比约18%,年增速32%;国内SaaS…

2026/11/5 11:39:15

PostgreSQL数据类型选择指南与性能优化实践

1. PostgreSQL数据类型概述PostgreSQL作为一款功能强大的开源关系型数据库,其数据类型系统之丰富远超大多数同类产品。我在实际项目中最常遇到的问题是:面对十几种数字类型、多种字符串类型以及各种特殊类型时,开发团队往往凭直觉选择&#x…

2026/11/5 11:34:12

Simulink S-function执行时序与状态管理原理详解

简介:本资源是面向MATLAB/Simulink初学者与控制系统建模学习者的S-Function入门实践包,聚焦自定义系统函数开发这一核心能力,解决标准库无法覆盖的特定数学运算与动态逻辑建模需求。压缩包共4个文件(2个M文件实现核心算法逻辑&…

2026/11/5 11:34:12

低空经济三维智能感知与实时调度技术解析

1. 低空经济三维空间智能感知与管控体系概述低空经济作为新兴经济形态,正在全球范围内快速发展。根据国际航空运输协会(IATA)预测,到2030年,全球城市空中交通市场规模将达到1.5万亿美元。在这一背景下,《低…

2026/11/5 11:34:12

链表数据结构与PTA解题技巧详解

1. 链表基础与数据结构课程实践 链表作为线性表的链式存储结构,是数据结构课程中承前启后的关键内容。在山东理工大学(SDUT)的数据结构与算法课程体系中,链表章节通常安排在顺序表之后、树结构之前,这种教学顺序设计体…

2026/11/5 11:34:12

Simulink S-Function核心机制与两个经典C示例解析

简介:本资源是面向MATLAB/Simulink初学者与控制系统建模学习者的S-Function入门实践包,聚焦自定义系统函数开发这一核心能力,解决标准库无法覆盖的特定数学运算与动态逻辑建模需求。压缩包共4个文件(2个M文件实现核心算法逻辑&…

2026/11/5 11:34:12

Mantle系统架构:云存储局部性与扩展性的突破

1. 项目概述:Mantle系统架构演进的技术突围在云存储技术高度成熟的今天,百度沧海存储团队完成的Mantle系统设计堪称一次教科书级别的技术突围。这个被SOSP25收录的存储系统创新案例,完美诠释了如何在看似饱和的技术领域实现突破——不是通过堆…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑