当前位置: 首页 > news >正文

HarmonyOS《柚兔学伴》项目实战19-云数据库——端云数据同步

第19篇:云数据库——端云数据同步

HarmonyOS 的云数据库(Cloud DB)提供了端云一致的数据存储方案,支持数据在本地和云端之间自动同步,实现跨设备数据共享。本篇以"柚兔学伴"项目为例,讲解如何使用@kit.CloudFoundationKit中的cloudDatabase模块完成云端数据的查询、插入与更新操作。


1. 云数据库基础概念

1.1 云数据库 vs 本地 RDB

特性云数据库 (Cloud DB)本地 RDB
数据存储位置云端 + 本地缓存仅本地
跨设备同步支持不支持
网络依赖首次查询需联网
适用场景用户共享数据、跨设备同步离线数据、本地缓存
数据类型DatabaseObject 子类ValuesBucket

在"柚兔学伴"中,AI 工具卡片(Tool)、用户单词本(Word)、长难句(Sentence)都存储在云数据库中,实现不同设备间的学习数据同步。

1.2 核心对象关系

cloudDatabase.zone(name) → DatabaseZone (数据区域) DatabaseQuery<T>(Class) → DatabaseQuery (查询条件) DatabaseZone.query(condition) → T[] (查询结果) DatabaseZone.upsert(data) → number (插入/更新)

2. 获取 DatabaseZone 实例

所有云数据库操作都从获取DatabaseZone开始,需要指定区域名称:

import{cloudDatabase}from'@kit.CloudFoundationKit';import{UrlConstants}from'network';agcDataBase:cloudDatabase.DatabaseZone=cloudDatabase.zone(UrlConstants.ZONE_NAME);

其中ZONE_NAMEUrlConstants中定义为常量:

exportclassUrlConstants{staticreadonlyZONE_NAME:string='Partner'}

注意:区域名称需与 AGC 控制台中配置的云数据库区域名称一致。

3. 定义云对象类型

云数据库中的每张表对应一个继承自cloudDatabase.DatabaseObject的类,通过naturalbase_ClassName()方法指定表名:

3.1 Tool(AI 工具卡片)

import{cloudDatabase}from'@kit.CloudFoundationKit';classToolextendscloudDatabase.DatabaseObject{id:number|undefined;name:string='';cover:string='';num:string|undefined;type:string|undefined;naturalbase_ClassName():string{return'Tool';}}export{Tool};

3.2 Word(单词卡片)

classWordextendscloudDatabase.DatabaseObject{id:number|undefined;name:string|undefined;ttsUrl:string|undefined;pronunciation:string|undefined;means:string|undefined;userId:string|undefined;publicnaturalbase_ClassName():string{return'Word';}}export{Word};

3.3 Sentence(长难句)

classSentenceextendscloudDatabase.DatabaseObject{id:number|undefined;src:string|undefined;dst:string|undefined;ttsUrl:string|undefined;userId:string|undefined;publicnaturalbase_ClassName():string{return'Sentence';}}export{Sentence};

设计要点:

  • naturalbase_ClassName()返回的名称必须与 AGC 控制台中定义的表名完全一致
  • 字段名与云数据库表中的列名对应
  • userId字段用于实现用户维度的数据隔离

4. 查询数据

4.1 ChatView:查询 Tool 列表

在聊天首页,加载所有 AI 工具卡片不需要按用户过滤:

@Componentexportstruct ChatView{agcDataBase:cloudDatabase.DatabaseZone|undefined=undefined;condition:cloudDatabase.DatabaseQuery<cloudDatabase.DatabaseObject>|undefined=undefined;@StatecardList:Tool[]=[]asyncaboutToAppear():Promise<void>{this.agcDataBase=cloudDatabase.zone(UrlConstants.ZONE_NAME);this.getCardList()}asyncgetCardList(){letcondition=newcloudDatabase.DatabaseQuery(Tool);try{this.cardList=awaitthis.agcDataBase!!.query(condition)hilog.info(0x0000,'testTag',`Succeeded in querying data, result:${JSON.stringify(this.cardList)}`);}catch(err){hilog.error(0x0000,'testTag',`Failed to query data, code:${err.code}, message:${err.message}`);}}}

查询流程:

  1. new cloudDatabase.DatabaseQuery(Tool)创建以 Tool 类为模板的查询条件
  2. 不添加任何条件,表示查询所有记录
  3. agcDataBase.query(condition)执行查询,返回Tool[]数组

4.2 WordCardPage:按用户查询单词

单词本需要只显示当前用户的单词,通过condition.equalTo('userId', uuid)实现数据隔离:

@Componentstruct WordCardPage{agcDataBase:cloudDatabase.DatabaseZone=cloudDatabase.zone(UrlConstants.ZONE_NAME);condition:cloudDatabase.DatabaseQuery<cloudDatabase.DatabaseObject>|undefined=undefined;@StatewordList:Word[]=[]aboutToAppear():void{this.getWordList().then((wordList:Word[])=>{this.wordList=wordList})}asyncgetWordList():Promise<Word[]>{try{this.condition=newcloudDatabase.DatabaseQuery(Word);letuuid=awaitUserInfoManager.getUserInfo()?.unionIDthis.condition.equalTo('userId',uuid)returnawaitthis.agcDataBase?.query(this.condition)asWord[]}catch(err){return[]}}}

用户数据隔离的关键步骤:

  1. 通过UserInfoManager.getUserInfo()?.unionID获取用户唯一标识
  2. condition.equalTo('userId', uuid)添加等值查询条件
  3. 查询结果只包含当前用户的单词数据

4.3 SentenceCardPage:按用户查询长难句

查询模式与 WordCardPage 完全一致,仅将类型替换为Sentence

@Componentstruct SentenceCardPage{agcDataBase:cloudDatabase.DatabaseZone=cloudDatabase.zone(UrlConstants.ZONE_NAME);condition:cloudDatabase.DatabaseQuery<cloudDatabase.DatabaseObject>|undefined=undefined;@StatesentenceList:Sentence[]=[]asyncgetWordList():Promise<Sentence[]>{try{this.condition=newcloudDatabase.DatabaseQuery(Sentence);letuuid=awaitUserInfoManager.getUserInfo()?.unionIDthis.condition.equalTo('userId',uuid)returnawaitthis.agcDataBase?.query(this.condition)asSentence[]}catch(err){return[]}}}

5. 插入与更新数据

5.1 upsert 操作

upsert是云数据库提供的"插入或更新"操作——如果记录已存在则更新,不存在则插入。在ChatView中可以看到注释中的 upsert 用法:

// 更新卡片点击次数data.num=(parseInt(data.num!!)+1).toString()this.agcDataBase!!.upsert(data).then((num:number)=>{this.getCardList()}).catch((err:BusinessError)=>{err})

5.2 创建新的云对象

添加长难句时,创建Sentence实例并设置字段值:

letsentence=newSentence();sentence.src=this.model.resultData.result!!.trans_result!![0].src sentence.dst=this.model.resultData.result!!.trans_result!![0].dst sentence.ttsUrl=this.model.resultData.result!!.trans_result!![0].dst_tts sentence.userId=UserInfoManager.getUserInfo()?.unionID// this.agcDataBase.upsert(sentence) // 插入到云端

步骤:

  1. new Sentence()创建空的云对象实例
  2. 设置各字段值,特别是userId确保数据归属
  3. agcDataBase.upsert(sentence)将数据写入云数据库

6. 错误处理

云数据库操作涉及网络请求,必须做好错误处理。项目中采用try/catch包裹查询操作:

asyncgetCardList(){letcondition=newcloudDatabase.DatabaseQuery(Tool);try{this.cardList=awaitthis.agcDataBase!!.query(condition)hilog.info(0x0000,'testTag',`Succeeded in querying data, result:${JSON.stringify(this.cardList)}`);}catch(err){hilog.error(0x0000,'testTag',`Failed to query data, code:${err.code}, message:${err.message}`);}}

对于非关键数据(如单词列表),查询失败时返回空数组:

asyncgetWordList():Promise<Word[]>{try{this.condition=newcloudDatabase.DatabaseQuery(Word);letuuid=awaitUserInfoManager.getUserInfo()?.unionIDthis.condition.equalTo('userId',uuid)returnawaitthis.agcDataBase?.query(this.condition)asWord[]}catch(err){return[]}}

错误处理建议:

场景处理方式
关键数据查询失败使用hilog.error记录,UI 显示错误提示
非关键数据查询失败返回空数组,UI 显示"暂无数据"
写入操作失败catch中提示用户重试
网络不可用结合本地缓存提供离线体验

7. UI 数据绑定

查询结果直接绑定到@State变量,实现数据驱动 UI 更新:

@StatecardList:Tool[]=[]@BuilderCardLayout(){Grid(this.scroller){ForEach(this.cardList,(data:Tool,index:number)=>{GridItem(){Column(){Column({space:5}){Row(){Text(data.name).fontWeight(FontWeight.Bold).fontColor(Color.White);Text('复习记忆').fontSize(10).fontColor(Color.White)}.width('100%').justifyContent(FlexAlign.SpaceBetween);}.width('100%').padding(10)}.backgroundImage(data.cover).width('100%').aspectRatio(1);}.onClick(()=>{if(index===1){this.pageContext.openPage({routerName:'WordCardPage'},true);}elseif(index===0){this.pageContext.openPage({routerName:'SentenceCardPage'},true);}});});}.columnsTemplate('1fr 1fr').columnsGap(10).rowsGap(10)}

单词列表页面,无数据时显示空状态:

if(this.wordList.length===0){Column({space:15}){Image($r('app.media.ic_no_data')).width(50)Text('点击对话记录中的单词可添加到单词卡片').fontSize(12)Text('暂无单词卡片').fontColor($r('app.color.color_divider')).fontSize(12)}.layoutWeight(1).justifyContent(FlexAlign.Center)}else{List({space:10}){ForEach(this.wordList,(word:Word,index:number)=>{ListItem(){Column({space:10}){Row({space:5}){Text(word.name).fontWeight(FontWeight.Bold).fontSize(18)Image($r('app.media.ic_listening')).width(24).onClick(()=>{this.model.download(word.ttsUrl!!).then((name:string)=>{AudioUtils.getInstance().startPlay(getContext(this).cacheDir+name)})})Blank()}.width('100%')Text(word.pronunciation).fontSize(12).width('100%')Text(word.means).fontSize(14).fontStyle(FontStyle.Italic)}.padding(12).alignItems(HorizontalAlign.Start)}.backgroundColor($r('app.color.color_card')).borderRadius(12)})}.layoutWeight(1)}

8. DatabaseQuery 条件构建

DatabaseQuery支持多种条件构建方式:

方法说明示例
equalTo(field, value)等值查询condition.equalTo('userId', uuid)
lessThan(field, value)小于condition.lessThan('age', 18)
greaterThan(field, value)大于condition.greaterThan('score', 60)
orderByDesc(field)降序排列condition.orderByDesc('date')
orderByAsc(field)升序排列condition.orderByAsc('name')
limit(count)限制返回数量condition.limit(10)

多条件组合:可以链式调用多个条件方法:

letcondition=newcloudDatabase.DatabaseQuery(Word);condition.equalTo('userId',uuid).orderByDesc('name').limit(20);

小结

本篇围绕 HarmonyOS 云数据库的核心操作展开讲解:

  1. 连接云数据库cloudDatabase.zone(name)获取DatabaseZone实例
  2. 定义云对象:继承DatabaseObject,实现naturalbase_ClassName()指定表名
  3. 查询数据DatabaseQuery<T>构建条件 →zone.query(condition)执行查询
  4. 数据隔离condition.equalTo('userId', uuid)实现用户维度过滤
  5. 写入数据zone.upsert(data)实现插入或更新
  6. 错误处理try/catch包裹异步操作,查询失败返回空数组
  7. UI 绑定:查询结果直接赋值@State变量,驱动界面自动刷新

云数据库为"柚兔学伴"实现了单词本、长难句等学习数据的端云同步,用户在不同设备上都能获取一致的学习进度。

http://www.jsqmd.com/news/1248943/

相关文章:

  • SwiftUI:iOS 常用视图组件速查
  • 数字同事:RPA+AI如何提升团队生产力
  • 静态原生IP代理配置指南:从原理到VMLogin实战应用
  • AI公司技术架构演进与商业化路径全解析
  • 具身视觉语言导航与问答技术解析与应用
  • 帝舵青岛售后门店核验指南|权威公告最新认证网点(2026年7月最新) - 帝舵售后服务中心官网
  • Java面试八股文1000问(2026金九银十版),涵盖基础/网络/算法/设计模式/多线程
  • 兰州2026瓷砖空鼓维修靠谱推荐:厨卫阳台地砖空鼓修复 - 筑宅安
  • 苏州闲置翡翠快速变现攻略,认准易奢福 31 年连锁大品牌更靠谱 - 遁地的c
  • Appium自动化测试:详解应用启动与退出的核心配置与最佳实践
  • 实用视频格式转换工具:转GIF、转音频和各类格式转换
  • YOLOv11多模态目标检测:FDAM模块提升特征融合效果
  • 制造业智能库存管理:ERP系统如何破解库存积压与缺料难题
  • 头风隐毒探因:铅汞毒与代谢毒的双重启示
  • 文字转图片工具:提升内容创作效率的必备利器
  • 智能体规划技术:ReAct、CoT与Planning解析
  • 通用CPU+GPU运行神经网络推理 VS RDK X5运行神经网络推理,前者CPU软件调度+GPU软件并行计算,包括数据预处理和神经网络模型推理;后者ISP + 芯片微码调度 + 硬件并行处理单元实现
  • 红桥区欧姆龙光电传感器公司推荐,欧姆龙位移传感器采购公司哪家好|天津本地工控元器件口碑推荐 - mobible
  • 北京腕表维修服务中心怎么选(2026年7月更新)——高端腕表复杂故障该去哪修? - 亨得利官方售后
  • 2026 年二建备考软件深度横评,自有电子版题库专属工具 - 讲清楚了
  • 解决99%部署报错!OpenClaw 2.7.9双系统安装与故障修复指南
  • 2026 济南名表卡地亚欧米茄回收渠道盘点,闲置腕表稳妥变现参考 - 资讯洞察员
  • 基于Hadoop+SparkML+Kafka的实时信用卡欺诈检测系统架构与实践
  • 2026年AI高薪岗位趋势与自学大模型避坑指南
  • 2026年全国塑烧板除尘器实力厂商TOP5推荐 - 品研笔录
  • AI工具助力本科生高效完成毕业论文写作
  • 基于OpenWrt软路由构建网络逆向分析平台:从协议探测到行为建模
  • AI智能写作工具如何提升学术论文效率与质量
  • 实测无坑|Hermes Windows 一体化包,快速搭建专属本地智能助手
  • 同城店铺曝光