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

发布时间:2026/7/15 0:22:30
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 分层架构项目适用于课程设计、毕设中笔记、通讯录、本地缓存等结构化数据持久化场景。