鸿蒙 韶非 UI 系列:关系数据库 @ohos.data.relationalStore,鸿蒙 SQLite 封装,结构化数据存取入门
写在前面如果你写过鸿蒙 ArkUI 应用大概率遇到过这个场景你写了个记账应用,每笔账有「金额/类型/时间/备注」四个字段。你想「用文件存 JSON 数组」——结果改一笔账要读全表、改、写全表,10 笔账卡得飞起。你想「用 Preferences 存」——Preferences 是键值对,不能按条件查「上个月吃饭花了多少」。你查文档发现「鸿蒙有 relationalStore,是 SQLite 封装」——你点进去发现getRdbStore拿实例、executeSql执行 DDL、insert(table, ValuesBucket)插数据、querySql返回ResultSet遍历、beginTransaction/commit/rollBack管事务——API 一脸懵。这是「键值对存」和「关系型存」的分水岭。鸿蒙给的结构化存取答案是ohos.data.relationalStore——getRdbStore拿数据库实例、executeSql执行建表/DDL、insert/ValuesBucket安全插入、querySql/ResultSet查询遍历、beginTransaction/commit/rollBack事务保证原子性。本文就用一个真机可跑的「建库 建表 插入 查询 事务」demo,把关系数据库从「听名字一脸懵」讲到「下个项目直接抄」。代码托管在 AtomGit,文末有链接,真机实拍截图作证。这是韶非 UI 系列第五篇,接续上四篇 HTTP 网络栈 文件 IO 能力调用 后台任务。适合人群:写过鸿蒙应用、被「记账应用用啥存」折磨过的同学。不适合人群:还在学State的同学——出门左转看我的入门篇。一、先讲清楚:关系数据库到底是啥一句话:关系数据库是鸿蒙给应用存「结构化数据」的原生机制,管「建库 建表 增删改查 事务」全流程。你之前写前端localStorage/IndexedDB是浏览器宿主 API——鸿蒙不是浏览器环境,没有这种。关系数据库是鸿蒙专门给结构化存取的原生机制,底层是 SQLite,能力对标前端的「IndexedDB SQL.js」但更精细可控。核心 API 一览:API作用一句话理解relationalStore.getRdbStore(context, config)拿 RdbStore 实例「告诉系统我要用数据库」rdbStore.executeSql(sql)执行 DDL/原始 SQL「建表/索引/原始 SQL」rdbStore.insert(table, ValuesBucket)插入数据「键值对插入,防 SQL 注入」rdbStore.querySql(sql)查询数据「SELECT 返回 ResultSet」rdbStore.beginTransaction/commit/rollBack事务管理「保证原子性,要么全成要么全回滚」记住这五个,往下看。二、动手:一个建库 建表 插入 查询 事务的 demo2.1 import 拿 UIAbilityContextimportrelationalStorefromohos.data.relationalStoreimportcommonfromohos.app.ability.commonEntryComponentstruct Index{privatecontext:common.UIAbilityContextgetContext(this)ascommon.UIAbilityContextprivaterdbStore:relationalStore.RdbStore|nullnullprivatedbName:stringarkts_demo.dbprivatetableName:stringUSER// ...}三个细节:import relationalStore from ohos.data.relationalStore——relationalStore是关系数据库的入口模块context: common.UIAbilityContext——RDB 是应用沙箱内建库,需 UIAbility 上下文定位沙箱rdbStore存拿到的 RdbStore 实例,后续所有操作都走它2.2getRdbStoreexecuteSql:初始化 建表asyncinitRdb():Promisevoid{this.stateLog初始化 RDB 中...try{constconfig:relationalStore.StoreConfig{name:this.dbName,securityLevel:relationalStore.SecurityLevel.S1}// getRdbStore 拿 RdbStore 实例沙箱内建库this.rdbStoreawaitrelationalStore.getRdbStore(this.context,config)// 建表 SQLCREATE TABLE IF NOT EXISTSconstcreateSqlCREATE TABLE IF NOT EXISTS${this.tableName}( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER, ts INTEGER )awaitthis.rdbStore.executeSql(createSql)this.stateLogRDB 已初始化,数据库 ${this.dbName},表 ${this.tableName}}catch(e){this.stateLog初始化失败:${e.message}this.rdbStorenull}}getRdbStore三个关键点:①StoreConfig配置:数据库名 安全级别constconfig:relationalStore.StoreConfig{name:this.dbName,// 数据库文件名沙箱内securityLevel:relationalStore.SecurityLevel.S1// 安全级别}SecurityLevel是鸿蒙定义的数据库安全级别:SecurityLevel含义用途S1低级公开数据普通应用S2中级个人数据记账/笔记S3高级敏感数据隐私相册S4最高严格机密金融/医疗S1 是默认选择。如果存用户隐私数据,选 S2/S3。②executeSql执行 DDL/原始 SQLawaitthis.rdbStore.executeSql(CREATE TABLE IF NOT EXISTS USER (...))executeSql执行建表/索引/原始 SQL,返回Promisevoid。注意:executeSql不返回查询结果——查询要走querySql。2.3insertValuesBucket:安全插入asyncinsertData():Promisevoid{if(!this.rdbStore){this.stateLog尚未初始化 RDB,无法插入return}try{constnow:numberDate.now()// ValuesBucket 键值对插入,比 raw SQL 安全防注入constbucket:relationalStore.ValuesBucket{name:user_${this.insertCount1},age:18(this.insertCount%30),ts:now}// insert 返回 rowIdconstrowId:numberawaitthis.rdbStore.insert(this.tableName,bucket)this.insertCountthis.stateLog第${this.insertCount}次插入成功,rowId ${rowId}}catch(e){this.stateLog插入失败:${e.message}}}insert三个关键点:①ValuesBucket键值对插入防 SQL 注入constbucket:relationalStore.ValuesBucket{name:user_${this.insertCount1},// 列名 - 值age:18(this.insertCount%30),ts:now}awaitthis.rdbStore.insert(this.tableName,bucket)ValuesBucket是「列名 - 值」的键值对。鸿蒙内部用参数化查询拼接,自动防 SQL 注入。比手写INSERT INTO ... VALUES (...)安全得多——手写 raw SQL 拼字符串,用户输入含就炸。②insert返回rowIdconstrowId:numberawaitthis.rdbStore.insert(this.tableName,bucket)rowId是新插入行的主键自增 ID,后续更新/删除可用它索引。2.4querySqlResultSet:查询遍历asyncqueryData():Promisevoid{if(!this.rdbStore){this.stateLog尚未初始化 RDB,无法查询return}try{// querySql 执行 SELECT,返回 ResultSetconstresultSet:relationalStore.ResultSetawaitthis.rdbStore.querySql(SELECT id, name, age, ts FROM${this.tableName}ORDER BY id DESC LIMIT 5)constrows:string[][]// ResultSet 遍历: goToFirstRow / goToNextRow / getColumnIndex / getString/getLongfor(leti0;resultSet.goToNextRow();i){constid:numberresultSet.getLong(resultSet.getColumnIndex(id))constname:stringresultSet.getString(resultSet.getColumnIndex(name))constage:numberresultSet.getLong(resultSet.getColumnIndex(age))rows.push(id${id}, name${name}, age${age})}// resultSet 用完必须 close 释放resultSet.close()this.queryCountthis.lastQueryResultrows.length0?rows.join(\n):(表为空)this.stateLog第${this.queryCount}次查询成功,返回${rows.length}行}catch(e){this.stateLog查询失败:${e.message}}}querySqlResultSet三个关键点:①querySql执行 SELECT 返回ResultSetconstresultSetawaitthis.rdbStore.querySql(SELECT ... FROM ...)ResultSet是游标,不是数组——初始指向「第一行之前」,要主动goToNextRow推进。②ResultSet遍历:游标推进 列索引取值for(leti0;resultSet.goToNextRow();i){constidresultSet.getLong(resultSet.getColumnIndex(id))constnameresultSet.getString(resultSet.getColumnIndex(name))// ...}goToNextRow():推进游标,返回false表示遍历完getColumnIndex(列名):拿列索引数字getLong/getDouble/getString(列索引):按类型取值③ResultSet用完必须close()resultSet.close()ResultSet持有底层 SQLite 游标资源,不 close 会内存泄漏。这是新手最容易忘的坑。2.5beginTransaction/commit/rollBack:事务保证原子性asyncrunTransaction():Promisevoid{if(!this.rdbStore){this.stateLog尚未初始化 RDB,无法跑事务return}try{// beginTransaction 开启事务this.rdbStore.beginTransaction()try{constnow:numberDate.now()// 批量插入 3 行for(leti0;i3;i){constbucket:relationalStore.ValuesBucket{name:tx_user_${now}_${i},age:20i,ts:now}awaitthis.rdbStore.insert(this.tableName,bucket)}// commitTransaction 提交事务this.rdbStore.commit()this.txLog事务提交成功,批量插入 3 行this.stateLog事务跑完了}catch(innerE){// rollBack 回滚事务this.rdbStore.rollBack()this.txLog事务回滚:${innerE.message}}}catch(e){this.stateLog事务失败:${e.message}}}事务三个关键点:①beginTransaction开启事务this.rdbStore.beginTransaction()// ← 之后所有 SQL 在同一事务内②commit提交 /rollBack回滚try{// ... 批量 SQL ...this.rdbStore.commit()// 全成,提交}catch(e){this.rdbStore.rollBack()// 失败,回滚所有}③ 事务保证原子性:要么全成要么全回滚事务最核心的价值是原子性——比如转账,扣 A 100 加 B 100 必须同时成,中间崩溃要么全成要么全回滚。没事务,扣 A 完崩溃,B 没加,钱凭空消失。三、真机实拍:建库 插入 查询 事务全跑通我把这个 demo 装到真机上跑鸿蒙 6.1.1.125, API 24依次点 ① 初始化 RDB ② 插入数据 ×2 ③ 查询数据 ④ 跑事务,下面两张都是真机实拍,没有任何 P 图。初始态:关系数据库 Demo 标题 状态区「尚未初始化 RDB」 ① 初始化 RDB / ② 插入数据 / ③ 查询数据 / ④ 跑事务四按钮 插入次数/查询次数指标区 最近查询结果区 事务日志区 关键 API 说明区:点 ① 初始化 ② 插入 ×2 ③ 查询 ④ 事务后状态:状态「RDB 已初始化,数据库 arkts_demo.db,表 USER」 插入次数 2 查询次数 1 最近查询结果显示 5 行(id/name/age) 事务日志「事务提交成功,批量插入 3 行」:重点看第二张:状态显示「RDB 已初始化,数据库 arkts_demo.db,表 USER」——getRdbStoreexecuteSql真建库建表了;插入次数 2 最近查询结果显示 5 行——insertquerySql真增真查了;事务日志「事务提交成功,批量插入 3 行」——beginTransaction/commit真事务跑了。这是 RDB 五大 API 全跑通的真机证明。四、relationalStorevs 前端「IndexedDB SQL.js」:啥差异新手最容易纠结的问题:既然前端IndexedDB那么标准,鸿蒙为啥要造关系数据库?维度前端「IndexedDB SQL.js」relationalStore运行环境浏览器宿主鸿蒙原生运行环境底层引擎IndexedDB / SQLite-WASMSQLite 原生编译API 风格异步回调 对象存储Promise SQL 风格安全模型同源策略鸿蒙沙箱 SecurityLevel事务 APItransaction隐式beginTransaction/commit显式性能JS-WASM 桥接,慢原生 SQLite,快一句话决策:鸿蒙应用存结构化数据必须用relationalStore,不能用IndexedDB不存在/localStorage容量小 不能条件查。鸿蒙不是浏览器,这套原生 SQLite 封装更安全可控、性能更高。五、常见坑都是血泪坑症状解法用localStorage/IndexedDB编译报错「找不到」鸿蒙用relationalStore,没浏览器宿主 APIexecuteSql拼 SQL 字符串SQL 注入风险查询用querySql,插入用insert ValuesBucketResultSet忘close()游标泄漏 后续查询卡用完务必resultSet.close()事务忘rollBack异常时数据不一致try/catch 内 catch 调rollBack跨应用共享数据库拿不到对方 RdbStore鸿蒙沙箱隔离,跨应用要 ohos.permissionSecurityLevel 选 S4普通应用拿不到 S4S4 限严格机密应用,普通用 S1/S2querySql期望返回数组编译报错类型不匹配返回ResultSet,要遍历六、relationalStore安全模型鸿蒙关系数据库受安全约束——沙箱隔离 SecurityLevel 分级:安全机制含义沙箱隔离数据库文件在应用沙箱内,其他应用默认访问不到SecurityLevel S1-S4数据库分级,S4 最严,限严格机密应用跨应用共享要ohos.permission权限 主动registerStoreObserver这是鸿蒙安全模型的硬约束——比浏览器IndexedDB同源策略严,但比 iOS Keychain 松鸿蒙沙箱可控粒度更细。七、完整代码仓库本文所有代码都已托管到AtomGit,欢迎 clone、提 issue、点 star:仓库地址:https://atomgit.com/JaneConan/arkui-rdb仓库包含:完整的「建库 建表 插入 查询 事务」demo 工程Index.ets主页面getRdbStoreexecuteSqlinsert/ValuesBucketquerySql/ResultSetbeginTransaction/commit/rollBack五姿势StoreConfig配置 SecurityLevel分级说明可直接用 DevEco Studio 打开运行真机装普通应用必能跑八、下一步该学什么?跑通这个 demo 之后,你的鸿蒙结构化存取就入门了。这是韶非 UI 系列第五篇,后续按这个顺序往下:WebSocketohos.net.webSocket下一篇:长连接、推送、实时通讯,聊天应用必学媒体访问ohos.file.photoAccessHelper:访问相册、扫描媒体文件,应用调系统相册必学推送通知ohos.notificationManager:通知栏展示、点击拉起,离线触达必学动画ohos.arkui.animation:属性动画、转场动画,UI 进阶必学相机ohos.multimedia.camera:预览、拍照、录像,相机应用必学写在最后relationalStore的本质,是**「鸿蒙给应用存结构化数据的原生 SQLite 封装」**——不是浏览器IndexedDB,是鸿蒙专门给关系型存取的原生机制,能力对标「IndexedDB SQL.js」但更安全可控、性能更高。代价是ValuesBucket键值对插入多一步、ResultSet游标遍历多一步。一旦你开始用关系数据库思维写结构化存取,你会发现大部分「记账应用按月查开销」「笔记应用按标签筛笔记」「待办按截止时间排」的需求,都是getRdbStoreexecuteSqlinsert/ValuesBucketquerySql/ResultSet的自然结果。代码量比localStorage多两行,结构化查询能力高九成。代码已经给你了,仓库链接在上面。现在关掉这篇文章,打开 DevEco Studio,把 demo 跑起来,亲手点建库建表插入查询事务五大姿势感受下结构化存取。跑通了,回来评论区打个「1」,我看看有多少人真的动手了。作者:JaneConan仓库:https://atomgit.com/JaneConan/arkui-rdb协议:Apache-2.0,随便用,别告我

相关新闻

ZFX山海证券:从公开信息出发,盘点服务体系与风险提示

ZFX山海证券:从公开信息出发,盘点服务体系与风险提示

外汇市场信息更新频繁,平台口碑的形成更依赖长期一致性:入口是否好找、说明是否前后一致、提示是否稳定出现。围绕ZFX山海证券,下面从稳定体验与信息呈现等角度做一次正面观察。外汇相关信息更新频繁,平台将关键提示与解释呈现得更…

2026/7/22 3:43:09 阅读更多 →
海外红队面试经验分享

海外红队面试经验分享

互联网公司A 老牌头部互联网公司,Top 10 职位:高级红队操作员 (Senior Red Team Operator) 流程 简历筛选 招聘人员电话面试: 背景、沟通能力、项目经验概述、对他们公司技术栈的初解 在线评估 : 基础编码/脚本能力测试 核心安全概念问答 (网络、操作系统、加密、认证) 重…

2026/7/26 9:21:40 阅读更多 →
总结 7.21

总结 7.21

今天学了线代的行列式和矩阵。行列式学了插型,剪头型还有ab型,ab型的计算公式。还有使用升阶法求行列式,把它化成剪型。还有范德蒙德,注意范德蒙德的阶数和为最高次数减一,然后递乘就行了,然后是算行列式的…

2026/7/26 9:20:55 阅读更多 →

最新新闻

计算机毕设简单的开题推荐

计算机毕设简单的开题推荐

1 引言 毕业设计是大家学习生涯的最重要的里程碑,它不仅是对四年所学知识的综合运用,更是展示个人技术能力和创新思维的重要过程。选择一个合适的毕业设计题目至关重要,它应该既能体现你的专业能力,又能满足实际应用需求&#xf…

2026/7/26 17:07:05 阅读更多 →
网安毕业设计2026方向汇总

网安毕业设计2026方向汇总

文章目录🚩 1 前言1.1 选题注意事项1.1.1 难度怎么把控?1.1.2 题目名称怎么取?1.2 选题推荐1.2.1 起因1.2.2 核心- 如何避坑(重中之重)1.2.3 怎么办呢?🚩2 选题概览🚩 3 项目概览题目1 : 大数据电商用户行为…

2026/7/26 17:07:05 阅读更多 →
Windows 11卸载搜狗输入法后任务栏卡顿解决方案

Windows 11卸载搜狗输入法后任务栏卡顿解决方案

1. 问题现象与背景分析 最近在Windows 11 23H2系统上遇到一个棘手问题:卸载搜狗输入法后,任务栏出现严重卡顿现象。具体表现为点击任务栏图标响应延迟高达3-5秒,右键菜单弹出缓慢,甚至有时会出现整个任务栏假死的情况。这个问题在…

2026/7/26 17:07:05 阅读更多 →
个人开发者从到(BeeCount:一款开源的跨平台个人记账应用)

个人开发者从到(BeeCount:一款开源的跨平台个人记账应用)

个人开发者从入门到实战:BeeCount——一款开源的跨平台个人记账应用 引言在数字时代,个人财务管理变得越来越重要。对于开发者来说,打造一款属于自己的记账应用,不仅能解决实际需求,还能深入理解前后端开发、数据持久化…

2026/7/26 17:07:05 阅读更多 →
Vuforia AR游戏开发实战:从环境搭建到性能优化的完整指南

Vuforia AR游戏开发实战:从环境搭建到性能优化的完整指南

1. 项目概述:从一份教程文件到AR游戏开发的实战蓝图看到这个文件名“VuforiaAR游戏设计与开发教程_2024-07-26_01-00-05.Tex”,我猜你和我一样,第一反应是:这大概是一份关于如何使用Vuforia引擎进行增强现实(AR&#x…

2026/7/26 17:07:05 阅读更多 →
DeepSeek V3.2多模态Agent与MCP平台技术解析

DeepSeek V3.2多模态Agent与MCP平台技术解析

1. 项目概述今天要跟大家分享一个重磅消息:DeepSeek V3.2正式版发布了!这次更新不仅带来了全新的官方Agent,还上线了多款MCP(Multi-Capability Platform)产品。作为一个长期关注AI技术发展的从业者,我第一时…

2026/7/26 17:06:05 阅读更多 →

日新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/26 0:00:31 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/26 0:00:31 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/26 0:00:31 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/26 0:00:31 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/26 0:00:31 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/26 0:00:31 阅读更多 →

月新闻