OpenHarmony RDB 关系型数据库增删改查全场景开发(API Version23 + 适配版)
摘要
RDB(关系型数据库)基于 SQLite 封装,适用于海量结构化、多字段复杂数据本地存储,如笔记、通讯录、商品列表、离线缓存等场景,弥补 Preferences 仅能存储简单键值的短板。API Version23 重构 RDB 数据库连接池、事务机制、异步 SQL 执行、游标内存回收逻辑,修复低版本数据库多次打开未关闭导致文件锁死、批量插入卡顿、游标泄漏、多表查询数据错乱、事务回滚失效等兼容缺陷。低版本工程升级至 API23 后常出现:数据库重复创建报错、查询游标未释放内存持续上涨、批量插入丢失数据、页面退出数据库无法关闭、分页查询偏移计算错误等问题。本文基于 DevEco Studio 适配 OpenHarmony API23 及以上版本,讲解数据库创建、表结构设计、单条 / 批量增删改查、分页查询、事务操作、数据库关闭销毁完整流程,以离线笔记管理系统为实战案例提供可直接运行代码,输出数据库连接复用、游标回收、事务容错规范,汇总版本升级兼容故障解决方案,为鸿蒙大量结构化数据持久化开发提供标准化实操模板。
关键词
OpenHarmony;ArkUI;API Version23;RDB;关系型数据库;SQLite;增删改查;事务;本地离线缓存
一、引言
1.1 RDB 数据库开发背景
Preferences 仅适合存储少量开关、用户名等简单键值数据,无法处理多字段、大批量结构化数据。RDB 基于标准 SQLite 实现,支持多数据表、条件筛选、分页、排序、事务批量操作,是离线笔记、通讯录、本地商品缓存、表单草稿等业务唯一轻量化数据库方案。
OpenHarmony API Version23 针对 RDB 底层引擎完成大规模升级,核心变更:
- 新增数据库连接池管理,避免重复打开数据库产生文件锁冲突;
- 强化 RdbStore 自动关闭机制,页面销毁自动释放连接,杜绝文件占用;
- 重构 ResultSet 游标内存回收逻辑,必须主动 close,否则持续内存泄漏;
- 标准化事务 begin/commit/rollback 执行顺序,修复低版本批量写入丢失;
- 统一 SQL 参数绑定防注入规则,禁止直接拼接字符串 SQL 语句;
- 限制超大无分页全表查询,超过 1000 条数据强制分页,防止页面卡顿。
旧项目随意打开数据库不关闭、拼接原始 SQL、游标不销毁的写法升级 API23 后极易闪退、内存溢出,因此掌握 API23 标准 RDB 开发规范是本地大数据存储必备技能。
1.2 开发环境与测试场景
开发工具:DevEco Studio 5.0 及以上 适配系统:OpenHarmony API Version23、HarmonyOS NEXT 开发语言:ArkTS 导入模块:@ohos.data.relationalStore 测试场景:笔记数据表创建、新增笔记、修改内容、单条 / 批量删除、分页查询、模糊搜索、事务批量插入、页面退出数据库释放
二、API23+ RDB 核心 API 与版本变更说明
2.1 数据库创建与获取
ets
import relationalStore from '@ohos.data.relationalStore'
// 数据库配置参数
const STORE_CONFIG: relationalStore.StoreConfig = {
name: "note_db", // 数据库文件名
securityLevel: relationalStore.SecurityLevel.S1
}
// 获取数据库实例(API23推荐单例全局复用)
let rdbStore: relationalStore.RdbStore | null = null
async function getRdbStore() {
if (!rdbStore) {
rdbStore = await relationalStore.getRdbStore(getContext(this), STORE_CONFIG)
// 首次打开自动建表
await createTable(rdbStore)
}
return rdbStore
}
2.2 核心 CRUD 操作 API
- insert (table, valuesBucket):插入单条数据,返回行 ID
- update (table, valuesBucket, predicates):按条件更新数据
- delete (table, predicates):条件删除数据
- query (table, columns, predicates):条件查询,返回 ResultSet 游标
- executeSql (sql, bindArgs):执行自定义 SQL 语句,支持批量事务
2.3 事务 API(API23 稳定)
- beginTransaction ():开启事务
- commit ():提交事务,数据永久写入
- rollback ():回滚,放弃本次所有修改
2.4 游标 ResultSet 强制规范
查询返回的 ResultSet 使用完毕必须调用resultSet.close(),API23 不再自动回收,遗漏会造成内存持续泄漏、数据库锁死。
2.5 API23 废弃与强制约束
- 废弃全局多处重复 getRdbStore 打开数据库,必须单例复用;
- 禁止直接拼接变量进 SQL 字符串,统一使用绑定参数防注入;
- 全表查询必须设置分页 offset/limit,禁止一次性加载上万条数据;
- 页面销毁必须调用 rdbStore.close () 释放连接;
- 不支持异步嵌套事务,同一时间仅允许一层事务执行。
三、API23 标准基础示例代码
3.1 建表语句(笔记表)
ets
async function createTable(store: relationalStore.RdbStore) {
const sql = `CREATE TABLE IF NOT EXISTS note(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT,
create_time INTEGER
)`
await store.executeSql(sql)
}
3.2 单条插入数据
ets
async function insertNote(store: relationalStore.RdbStore, title:string, content:string) {
let bucket: relationalStore.ValuesBucket = {
title: title,
content: content,
create_time: new Date().getTime()
}
let rowId = await store.insert("note", bucket)
return rowId
}
3.3 分页条件查询
ets
async function queryNotePage(store: relationalStore.RdbStore, page:number, size:number) {
let predicates = new relationalStore.RdbPredicates("note")
predicates.orderBy("create_time", false) // 时间倒序
predicates.offset(page * size).limit(size)
let resultSet = await store.query("note", ["id","title","content","create_time"], predicates)
let list = []
while(resultSet.goToNextRow()) {
list.push({
id: resultSet.getLong(0),
title: resultSet.getString(1),
content: resultSet.getString(2),
create_time: resultSet.getLong(3)
})
}
// API23强制关闭游标
resultSet.close()
return list
}
3.4 根据 ID 删除数据
ets
async function deleteNoteById(store: relationalStore.RdbStore, id:number) {
let predicates = new relationalStore.RdbPredicates("note")
predicates.equalTo("id", id)
let delCount = await store.delete("note", predicates)
return delCount
}
四、完整实战案例:离线笔记数据库管理(全兼容 API23)
4.1 全局 RDB 工具类封装(utils/rdb_util.ets)
ets
import relationalStore from '@ohos.data.relationalStore'
import common from '@ohos.app.ability.common'
// 数据库配置
const DB_CONFIG: relationalStore.StoreConfig = {
name: "note_database",
securityLevel: relationalStore.SecurityLevel.S1
}
class RdbUtil {
private static instance: RdbUtil
private rdbStore: relationalStore.RdbStore | null = null
private context: common.UIAbilityContext | null = null
static getInstance(): RdbUtil {
if (!RdbUtil.instance) {
RdbUtil.instance = new RdbUtil()
}
return RdbUtil.instance
}
// 初始化数据库,首页调用一次
async init(ctx: common.UIAbilityContext) {
this.context = ctx
if (!this.rdbStore) {
this.rdbStore = await relationalStore.getRdbStore(this.context, DB_CONFIG)
await this.createNoteTable()
}
}
// 创建笔记数据表
private async createNoteTable() {
const createSql = `CREATE TABLE IF NOT EXISTS note(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT,
create_time INTEGER
)`
await this.rdbStore!.executeSql(createSql)
}
// 新增笔记
async addNote(title: string, content: string): Promise<number> {
if (!this.rdbStore) return -1
let bucket: relationalStore.ValuesBucket = {
title,
content,
create_time: new Date().getTime()
}
return await this.rdbStore.insert("note", bucket)
}
// 根据id修改笔记
async updateNote(id: number, title: string, content: string): Promise<number> {
if (!this.rdbStore) return 0
let bucket: relationalStore.ValuesBucket = { title, content }
let predicates = new relationalStore.RdbPredicates("note")
predicates.equalTo("id", id)
return await this.rdbStore.update("note", bucket, predicates)
}
// 根据id删除单条笔记
async deleteNote(id: number): Promise<number> {
if (!this.rdbStore) return 0
let predicates = new relationalStore.RdbPredicates("note")
predicates.equalTo("id", id)
return await this.rdbStore.delete("note", predicates)
}
// 分页查询所有笔记,时间倒序
async queryNoteList(page: number, pageSize: number) {
if (!this.rdbStore) return []
let predicates = new relationalStore.RdbPredicates("note")
predicates.orderBy("create_time", false)
predicates.offset(page * pageSize).limit(pageSize)
let resultSet = await this.rdbStore.query("note", ["id","title","content","create_time"], predicates)
let dataList = []
while (resultSet.goToNextRow()) {
dataList.push({
id: resultSet.getLong(0),
title: resultSet.getString(1),
content: resultSet.getString(2),
create_time: resultSet.getLong(3)
})
}
// API23强制释放游标
resultSet.close()
return dataList
}
// 模糊搜索笔记标题
async searchNote(keyword: string) {
if (!this.rdbStore) return []
let predicates = new relationalStore.RdbPredicates("note")
predicates.like("title", `%${keyword}%`)
let resultSet = await this.rdbStore.query("note", ["id","title","content"], predicates)
let list = []
while (resultSet.goToNextRow()) {
list.push({
id: resultSet.getLong(0),
title: resultSet.getString(1),
content: resultSet.getString(2)
})
}
resultSet.close()
return list
}
// 事务批量插入测试数据
async batchInsertTest(amount: number) {
if (!this.rdbStore) return
try {
this.rdbStore.beginTransaction()
for(let i=0;i<amount;i++) {
let bucket = { title:`测试笔记${i}`, content:"批量事务插入内容", create_time:Date.now() }
await this.rdbStore.insert("note", bucket)
}
this.rdbStore.commit()
} catch(e) {
this.rdbStore.rollback()
console.error("批量插入失败,事务回滚", e)
}
}
// 关闭数据库,页面销毁调用
async closeDB() {
if (this.rdbStore) {
await this.rdbStore.close()
this.rdbStore = null
}
}
}
export default RdbUtil.getInstance()
4.2 笔记列表主页面(新增、分页、删除、搜索)
ets
import rdbUtil from '../utils/rdb_util'
import promptAction from '@ohos.promptAction'
import CustomDialog from '../components/InputDialog'
interface NoteItem {
id: number
title: string
content: string
create_time: number
}
@Entry
@Component
struct NoteRdbPage {
@State noteList: NoteItem[] = []
@State pageIndex: number = 0
readonly PAGE_SIZE = 10
dialogCtrl: CustomDialogController | null = null
async aboutToAppear() {
// 初始化数据库
await rdbUtil.init(getContext(this))
await this.loadNoteData()
}
// 分页加载数据
async loadNoteData() {
let data = await rdbUtil.queryNoteList(this.pageIndex, this.PAGE_SIZE)
if(this.pageIndex === 0) {
this.noteList = data
} else {
this.noteList = [...this.noteList, ...data]
}
}
// 新增笔记弹窗
openAddDialog() {
this.dialogCtrl = new CustomDialogController({
builder: CustomDialog({
submit: async (title, content) => {
await rdbUtil.addNote(title, content)
promptAction.showToast({message:"新增成功"})
this.pageIndex = 0
await this.loadNoteData()
}
}),
autoCancel:true
})
this.dialogCtrl.open()
}
// 删除笔记
async deleteItem(id: number) {
await rdbUtil.deleteNote(id)
promptAction.showToast({message:"删除完成"})
this.pageIndex = 0
await this.loadNoteData()
}
build() {
Column({space:15}) {
Row() {
Button("新增笔记").onClick(()=>this.openAddDialog())
Button("加载下一页").onClick(async ()=>{
this.pageIndex++
await this.loadNoteData()
})
}
List({space:12}) {
ForEach(this.noteList, (item:NoteItem)=>{
ListItem() {
Row() {
Column({space:6}).layoutWeight(1) {
Text(item.title).fontSize(18).fontWeight(FontWeight.Medium)
Text(item.content).fontSize(14).fontColor("#666")
}
Button("删除").backgroundColor("#f56c6c")
.onClick(async ()=>await this.deleteItem(item.id))
}
.width("100%")
.padding(15)
.backgroundColor(Color.White)
.borderRadius(10)
}
})
}
.layoutWeight(1)
}
.width("100%")
.height("100%")
.padding(15)
.backgroundColor("#F5F5F5")
}
async aboutToDisappear() {
// 页面销毁关闭数据库释放资源 API23必需
await rdbUtil.closeDB()
}
}
4.3 新增笔记弹窗组件
ets
@CustomDialog
struct InputDialog {
controller: CustomDialogController
@DialogParam submit: (title:string, content:string)=>void
@State title: string = ""
@State content: string = ""
build() {
Column({space:20}) {
Text("新建笔记").fontSize(22).fontWeight(FontWeight.Bold)
TextInput({text:this.title, placeholder:"标题"})
.width("100%").height(46)
TextInput({text:this.content, placeholder:"内容"})
.width("100%").height(46)
Row({space:15}) {
Button("取消").layoutWeight(1).onClick(()=>this.controller.close())
Button("保存").layoutWeight(1).backgroundColor("#007DFF")
.onClick(async ()=>{
if(!this.title) return promptAction.showToast({message:"标题不能为空"})
this.submit(this.title, this.content)
this.controller.close()
})
}
}
.width(340)
.padding(24)
.backgroundColor(Color.White)
.borderRadius(16)
}
}
五、API23+ RDB 数据库适配与性能优化规范
5.1 数据库连接规范
- 全局单例工具类管理 RdbStore,全程仅打开一次数据库;
- 页面销毁生命周期
aboutToDisappear调用 close () 关闭连接,释放文件锁; - 禁止多页面同时重复执行 getRdbStore,会触发文件占用报错。
5.2 游标内存强制规范
- 所有 query 查询返回 ResultSet,循环读取完毕必须执行
resultSet.close(); - 禁止提前 return 跳过 close,使用 try-finally 包裹游标逻辑保证释放;
- 长列表分页一次性读取不超过 100 条,减少游标内存占用。
5.3 事务批量操作规范
- 批量插入、批量更新统一使用事务,中途异常自动 rollback 回滚;
- 事务内避免复杂异步逻辑阻塞,仅执行数据库 CRUD;
- 禁止嵌套事务,API23 仅支持单层事务执行。
5.4 SQL 安全规范
- 禁止字符串拼接变量构造 SQL,全部使用 ValuesBucket 参数绑定;
- 模糊查询 like 语句统一使用
%关键字%绑定,防止 SQL 注入漏洞。
六、API23 升级高频兼容问题与解决方案
问题 1:多次进入页面提示数据库文件被占用、打开失败 解决:全局单例复用 RdbStore,页面销毁执行 close 关闭数据库连接。
问题 2:页面多次查询后内存持续上涨、应用卡顿闪退 解决:所有 ResultSet 读取完成强制调用 close 释放游标,不要遗漏。
问题 3:批量插入部分数据丢失,重启数据库数据不全 解决:批量操作包裹事务 begin/commit,捕获异常执行 rollback 回滚。
问题 4:升级 API23 后直接拼接 SQL 语句编译警告、存在安全风险 解决:全部替换为 RdbPredicates 条件查询、ValuesBucket 参数绑定。
问题 5:全表查询上千条数据页面滑动严重掉帧 解决:统一分页 offset+limit 加载,禁止一次性查询全部数据。
问题 6:页面退出再次进入,数据库无响应卡死 解决:页面销毁执行 close 关闭实例,下次进入重新初始化。
七、总结
RDB 关系型数据库是 OpenHarmony 处理大批量结构化离线数据的核心存储方案,API Version23 重构数据库连接、游标回收、事务底层逻辑,强化资源释放强制约束,大幅优化内存占用与并发读写稳定性。项目标准分层存储架构:少量配置使用 Preferences、海量结构化数据使用 RDB、全局内存缓存使用 AppStorage。
更多推荐



所有评论(0)