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

HarmonyOS NEXT 使用 relationalStore 实现数据库操作

大家好,我是V哥。在 HarmonyOS NEXT 开发中,如何操作数据库,V 哥在测试中总结了以下学习代码,分享给你,如何想要系统学习鸿蒙开发,可以了解一下 V 哥最近刚刚上架出版的 《HarmonyOS 鸿蒙开发之路 卷2 从入门到应用篇》,V 哥在这本书里系统的介绍纯血鸿蒙的细枝末节,可以让零基础的朋友快速上手鸿蒙应用开发。

在鸿蒙开发中,系统 API 提供了基于SQLite组件的一套完整的对本地数据库进行管理的机制,对外提供了一系列的增、删、改、查等接口,也可以直接运行用户输入的SQL语句来满足复杂的场景需要。支持通过ResultSet.getSendableRow方法获取Sendable数据,进行跨线程传递。

这里要注意一下,为保证插入并读取数据成功,建议一条数据不超过2MB。如果数据超过2MB,插入操作将成功,读取操作将失败。

大数据量场景下查询数据可能会导致耗时长甚至应用卡死,如有相关操作可参考文档批量数据写数据库场景,且有建议如下:

  • 单次查询数据量不超过5000条。
  • 在TaskPool中查询。
  • 拼接SQL语句尽量简洁。
  • 合理地分批次查询。

该模块提供以下关系型数据库相关的常用功能:

  • RdbPredicates:数据库中用来代表数据实体的性质、特征或者数据实体之间关系的词项,主要用来定义数据库的操作条件。
  • RdbStore:提供管理关系数据库(RDB)方法的接口。
  • ResultSet:提供用户调用关系型数据库查询接口之后返回的结果集合。
  • Transaction:提供管理事务对象的接口。

案例代码

接下来,V 哥通一个完整案例来介绍如何使用。


import relationalStore from '@ohos.data.relationalStore';
import promptAction from '@ohos.promptAction';@Entry
@Component
struct RdbStoreExample {@State userList: Array<{ id: number; name: string; age: number }> = [];@State nameInput: string = '';@State ageInput: string = '';private rdbStore: relationalStore.RdbStore | null = null;private rdbConfig: relationalStore.RdbStoreConfig = {name: 'UserData.db',securityLevel: relationalStore.SecurityLevel.S1};private CREATE_TABLE_USER = 'CREATE TABLE IF NOT EXISTS User (' +'id INTEGER PRIMARY KEY AUTOINCREMENT, ' +'name TEXT NOT NULL, ' +'age INTEGER NOT NULL)';aboutToAppear() {this.openRdbStore();}aboutToDisappear() {this.closeRdbStore();}// 打开数据库async openRdbStore() {try {this.rdbStore = await relationalStore.getRdbStore(this.rdbConfig, 1, (version: number, rdbStore: relationalStore.RdbStore) => {if (version === 1) {rdbStore.executeSql(this.CREATE_TABLE_USER, []);}});await this.queryUsers();} catch (error) {console.error(`Failed to open RDB store: ${error}`);promptAction.showToast({ message: '数据库打开失败' });}}// 关闭数据库async closeRdbStore() {if (this.rdbStore) {try {await this.rdbStore.close();this.rdbStore = null;} catch (error) {console.error(`Failed to close RDB store: ${error}`);}}}// 插入数据async insertUser() {if (!this.nameInput || !this.ageInput) {promptAction.showToast({ message: '请输入姓名和年龄' });return;}try {const valuesBucket = {name: this.nameInput,age: parseInt(this.ageInput)};const id = await this.rdbStore?.insert('User', valuesBucket);if (id && id > 0) {promptAction.showToast({ message: '插入成功' });await this.queryUsers();this.nameInput = '';this.ageInput = '';}} catch (error) {console.error(`Failed to insert data: ${error}`);promptAction.showToast({ message: '插入失败' });}}// 查询数据async queryUsers() {try {const resultSet = await this.rdbStore?.querySql('SELECT * FROM User', []);if (resultSet) {const users = [];resultSet.goToFirstRow();while (!resultSet.isAtEnd()) {users.push({id: resultSet.getLong(resultSet.getColumnIndex('id')),name: resultSet.getString(resultSet.getColumnIndex('name')),age: resultSet.getInt(resultSet.getColumnIndex('age'))});resultSet.goToNextRow();}this.userList = users;resultSet.close();}} catch (error) {console.error(`Failed to query data: ${error}`);promptAction.showToast({ message: '查询失败' });}}// 更新数据async updateUser(id: number, name: string, age: number) {try {const valuesBucket = {name: name,age: age};const conditions = new relationalStore.RdbStorePredicates('User');conditions.equalTo('id', id.toString());const rowsAffected = await this.rdbStore?.update(valuesBucket, conditions);if (rowsAffected && rowsAffected > 0) {promptAction.showToast({ message: '更新成功' });await this.queryUsers();}} catch (error) {console.error(`Failed to update data: ${error}`);promptAction.showToast({ message: '更新失败' });}}// 删除数据async deleteUser(id: number) {try {const conditions = new relationalStore.RdbStorePredicates('User');conditions.equalTo('id', id.toString());const rowsAffected = await this.rdbStore?.delete(conditions);if (rowsAffected && rowsAffected > 0) {promptAction.showToast({ message: '删除成功' });await this.queryUsers();}} catch (error) {console.error(`Failed to delete data: ${error}`);promptAction.showToast({ message: '删除失败' });}}build() {Column() {// 输入表单Column() {Input({placeholder: '请输入姓名',type: InputType.Text}).width('100%').margin({ top: 10, bottom: 10 }).onChange((value: string) => {this.nameInput = value;})Input({placeholder: '请输入年龄',type: InputType.Number}).width('100%').margin({ top: 10, bottom: 10 }).onChange((value: string) => {this.ageInput = value;})Button('添加用户').width('100%').onClick(() => {this.insertUser();})}.width('90%').margin({ top: 20, bottom: 20 })// 用户列表List() {ForEach(this.userList, (user) => {ListItem() {Row() {Column() {Text(`姓名: ${user.name}`)Text(`年龄: ${user.age}`)}.width('70%')Column() {Button('修改').onClick(() => {const newName = promptAction.showPromptDialog({message: '请输入新姓名',defaultValue: user.name});const newAge = promptAction.showPromptDialog({message: '请输入新年龄',defaultValue: user.age.toString()});if (newName && newAge) {this.updateUser(user.id, newName, parseInt(newAge));}})Button('删除').onClick(() => {this.deleteUser(user.id);})}.width('30%')}.width('100%')}})}.width('90%').margin({ top: 10, bottom: 10 })}.width('100%').height('100%').padding(15)}
}

下面来解释下这个示例:

  1. 首先要创建数据库配置并打开数据库,在openRdbStore方法里完成这些操作,创建了一个名为UserData.db的数据库,还定义了建表语句。

  2. 插入数据时,使用insert方法,把姓名和年龄封装成valuesBucket对象传进去,插入成功后会更新用户列表。

  3. 查询数据是通过querySql方法执行SQL语句,然后遍历结果集把数据存到userList里。

  4. 更新数据用update方法,要先创建RdbStorePredicates对象设置更新条件,根据ID来更新对应的记录。

  5. 删除数据也是先创建条件对象,然后调用delete方法,根据ID删除记录。

  6. 在界面上,提供了输入框让用户输入姓名和年龄,还有添加按钮,下面展示用户列表,每条记录都有修改和删除按钮。

操作技巧总结如下

  1. 打开和关闭数据库操作要在页面生命周期的合适时机进行,比如在aboutToAppear时打开,aboutToDisappear时关闭。
  2. 执行数据库操作时一定要进行异常处理,避免程序崩溃。
  3. 使用预编译语句可以提高性能,特别是在批量操作的时候。
  4. 操作完成后要及时关闭ResultSet,释放资源。
  5. 合理设计表结构,设置合适的主键和索引能提升查询效率。
  6. 更新和删除操作记得设置好条件,防止误操作。
  7. 对于复杂查询,可以使用原生SQL语句,但要注意SQL注入问题。

好了,以上内容供你参考,学习鸿蒙开发,抢占市场风口,国产化之路,V 哥与你搀扶前行。

相关文章:

HarmonyOS NEXT 使用 relationalStore 实现数据库操作

大家好&#xff0c;我是V哥。在 HarmonyOS NEXT 开发中&#xff0c;如何操作数据库&#xff0c;V 哥在测试中总结了以下学习代码&#xff0c;分享给你&#xff0c;如何想要系统学习鸿蒙开发&#xff0c;可以了解一下 V 哥最近刚刚上架出版的 《HarmonyOS 鸿蒙开发之路 卷2 从入…...

R语言学习--Day04--数据分析技巧

在清洗完数据&#xff0c;在对数据分析前&#xff0c;我们要懂得先梳理一下我们的逻辑&#xff0c;即数据是什么形式的&#xff0c;要进行哪种分析&#xff0c;有可能呈现什么特点&#xff0c;进而再想怎么处理数据去画图可以最大程度地凸显我们要的特点。 一般来讲&#xff0…...

SRS流媒体服务器之RTC播放环境搭建

环境概述 srs版本 commit 44f0c36b61bc7c3a1d51cb60be0ec184c840f09d Author: winlin <winlinvip.126.com> Date: Wed Aug 2 10:34:41 2023 0800Release v4.0-r5, 4.0 release5, v4.0.271, 145574 lines. rtc.conf # WebRTC streaming config for SRS. # see full.…...

Android 性能优化入门(三)—— ANR 问题分析

需要清楚 ANR 的概念、类型、如何产生以及如何定位分析。 1、概述 1.1 ANR 的概念 ANR&#xff08;Application Not Responding&#xff09;应用程序无响应。如果你应用程序在主线程被阻塞太长时间&#xff0c;就会出现 ANR&#xff0c;通常出现 ANR&#xff0c;系统会弹出一…...

用HTML5实现实时ASCII艺术摄像头

用HTML5实现实时ASCII艺术摄像头 项目简介 这是一个将摄像头画面实时转换为ASCII字符艺术的Web应用&#xff0c;基于HTML5和原生JavaScript实现。通过本项目可以学习到&#xff1a; 浏览器摄像头API的使用Canvas图像处理技术实时视频流处理复杂DOM操作性能优化技巧 功能亮点…...

鸿蒙Flutter实战:22-混合开发详解-2-Har包模式引入

以 Har 包的方式加载到 HarmonyOS 工程 创建工作 创建一个根目录 mkdir ohos_flutter_module_demo这个目录用于存放 flutter 项目和鸿蒙项目。 创建 Flutter 模块 首先创建一个 Flutter 模块&#xff0c;我们选择与 ohos_app 项目同级目录 flutter create --templatemodu…...

游戏引擎学习第302天:使用精灵边界进行排序

在 game_render_group.cpp 中&#xff1a;正确计算 GetBoundFor() 里的 SpriteBound 值 我们正在进行游戏的排序问题调试。虽然这是一个二维游戏&#xff0c;但包含一些三维元素&#xff0c;因此排序变得比较复杂和棘手。混合二维和三维元素时&#xff0c;需要依赖一些比较主观…...

SpringBoot+MyBatis

切换数据库连接词 引入数据库连接词的依赖&#xff0c;配置数据库连接池的类型&#xff1b; 编写测试类&#xff1a; package org.example.threelayerdecouplingdomeapplication2;import org.example.threelayerdecouplingdomeapplication2.mapper.UserMapper; import org.ex…...

wireshark: Display Filter Reference

https://www.wireshark.org/docs/dfref/// 这个里面的扩展功能还是很强大&#xff0c;可以帮着问题分析。支持大量的自定义化的字段读取功能&#xff0c;支持很多的协议。 https://www.wireshark.org/docs/dfref///f/frame.html frame.time_delta Time delta from previous ca…...

Java基础 Day19

一、泛型&#xff08;JDK5引入&#xff09; 1、基本概念 在编译阶段约束操作的数据类型&#xff0c;并进行检查 好处&#xff1a;统一数据类型&#xff0c;将运行期的错误提升到了编译期 泛型的默认类型是 Object 2、泛型类 在创建类的时候写上泛型 在创建具体对象的时候…...

VMware+Windows 11 跳过安装阶段微软账号登录

OOBE 阶段 来到这里 断开网络适配器 VMware右下角&#xff0c;点击网络适配器&#xff0c;断开连接 同时按下 Shift 和 F10 &#xff0c;打开命令提示符(cmd.exe) 输入 oobe\BypassNRO.cmd 并回车 接下来正常进行即可...

HarmonyOS开发-应用间跳转

1. HarmonyOS开发-应用间跳转 在鸿蒙中,我们再开发过程当中或多或少都会遇见想要从一个App的页面跳转至另一个App的页面,这个时候我们要怎么进行跳转呢,其实在HarmonyOS开发者文档中只需要用到Want对象和startAbility()方法进行跳转就可以了。 1.1. 实现 (1)我们要先准备两个…...

网工每日一练

2025/5/22.每日一练&#xff08;单选题&#xff09; 路由器在查找路由表时存在最长匹配原则&#xff0c;这里的长度指的是以下哪个参数&#xff1f; A. NextHopIP地址的大小 B. 路由协议的优先级 C. Cost D. 掩码的长度 路由器在查找路由表时遵循的最长匹配原则中&#xff0c;“…...

使用 Navicat 17 for PostgreSQL 时,请问哪个版本支持 PostgreSQL 的 20150623 版本?还是每个版本都支持?

&#x1f9d1;‍&#x1f4bb; PostgreSQL 用户 使用 Navicat 17 for PostgreSQL 时&#xff0c;请问哪个版本支持 PostgreSQL 的 20150623 版本&#xff1f;还是每个版本都支持&#xff1f; &#x1f9d1;‍&#x1f527; 官方技术中心 Navicat Premium 17 和 Navicat for P…...

校园二手交易系统

该交易平台分为两部分&#xff0c;前台和后台。用户在前台进行商品选购以及交易&#xff1b;管理员登录后台可以对商品进行维护&#xff0c;主要功能包含&#xff1a; 后台系统的主要功能模块如下&#xff1a; 登录功能、注册功能、后台首页 系统设置&#xff1a; 菜单管理、…...

基于pycharm,python,flask,sklearn,orm,mysql,在线深度学习sql语句检测系统

详细视频:【基于pycharm,python,flask,sklearn,orm,mysql&#xff0c;在线深度学习sql语句检测系统-哔哩哔哩】 https://b23.tv/JLQDwNn...

LangChain02-Agent与Memory模块

Agent与Memory模块深度解析 1. Agent模块原理 1.1 ReAct框架的实现机制 Agent是LangChain中最具智能化的组件&#xff0c;其核心思想基于 ReAct框架&#xff08;Reasoning Acting&#xff09;&#xff0c;即通过 思维&#xff08;Thought&#xff09; 和 行动&#xff08;Ac…...

upload-labs通关笔记-第17关文件上传之二次渲染gif格式

系列目录 upload-labs通关笔记-第1关 文件上传之前端绕过&#xff08;3种渗透方法&#xff09; upload-labs通关笔记-第2关 文件上传之MIME绕过-CSDN博客 upload-labs通关笔记-第3关 文件上传之黑名单绕过-CSDN博客 upload-labs通关笔记-第4关 文件上传之.htacess绕过-CSDN…...

计算机网络学习20250525

应用层协议原理 创建一个网络应用,编写应用程序,这些应用程序运行在不同的端系统上,通过网络彼此通信 不需要在网络核心设备(路由器,交换机)上写应用程序网络应用程序工作在网络层以下将应用程序限制在端系统上促进应用程序迅速研发和部署,将复杂问题放到网络边缘网络应…...

STM32中的SPI通信协议

IIC和SPI的对比 IIC是半双工的通信&#xff0c;无法同时收发信息&#xff1b;SPI是全双工通讯&#xff0c;可以同时收发信息&#xff1b;IIC的通讯协议较复杂&#xff0c;而SPI通讯协议较简单&#xff1b;IIC需要通过地址选择从机&#xff0c;而SPI只主要一个引脚即可选中从机…...

从版本控制到协同开发:深度解析 Git、SVN 及现代工具链

前言&#xff1a;在当今软件开发的浪潮中&#xff0c;版本控制与协同开发无疑扮演着举足轻重的角色。从最初的单兵作战到如今大规模团队的高效协作&#xff0c;一套成熟且得力的版本控制系统以及围绕其构建的现代工具链&#xff0c;已然成为推动软件项目稳步前行的关键引擎。今…...

redis Pub/Sub 简介 -16 (PUBLISH、SUBSCRIBE、PSUBSCRIBE)

Redis Pub/Sub 简介&#xff1a;PUBLISH、SUBSCRIBE、PSUBSCRIBE Redis Pub/Sub 是一种强大的消息传递范例&#xff0c;可在应用程序的不同部分之间实现实时通信。它是构建可扩展和响应式系统的基石&#xff0c;允许组件在没有直接依赖的情况下进行交互。本章将全面介绍 Redis…...

《黄帝内经》数学建模与形式化表征方式的重构

黄帝内经的数学概括&#xff1a;《黄帝内经》数学建模与形式化表征方式的重构 摘要&#xff1a;《黄帝内经》通过现代数学理论如动力系统、代数拓扑和随机过程&#xff0c;被重构为一个形式化的人体健康模型。该模型包括阴阳动力学的微分几何、五行代数的李群结构、经络拓扑与同…...

PyTorch Image Models (timm) 技术指南

timm PyTorch Image Models (timm) 技术指南功能概述 一、引言二、timm 库概述三、安装 timm 库四、模型加载与推理示例4.1 通用推理流程4.2 具体模型示例4.2.1 ResNeXt50-32x4d4.2.2 EfficientNet-V2 Small 模型4.2.3 DeiT-3 large 模型4.2.4 RepViT-M2 模型4.2.5 ResNet-RS-1…...

基于Scikit-learn与Flask的医疗AI糖尿病预测系统开发实战

引言 在精准医疗时代&#xff0c;人工智能技术正在重塑临床决策流程。本文将深入解析如何基于MIMIC-III医疗大数据集&#xff0c;使用Python生态构建符合医疗AI开发规范的糖尿病预测系统。项目涵盖从数据治理到模型部署的全流程&#xff0c;最终交付符合DICOM标准的临床决策支…...

掌握聚合函数:COUNT,MAX,MIN,SUM,AVG,GROUP BY和HAVING子句的用法,Where和HAVING的区别

对于Java后端开发来说&#xff0c;必须要掌握常用的聚合函数&#xff1a;COUNT&#xff0c;MAX&#xff0c;MIN&#xff0c;SUM&#xff0c;AVG&#xff0c;掌握GROUP BY和HAVING子句的用法&#xff0c;掌握Where和HAVING的区别&#xff1a; ✅ 一、常用聚合函数&#xff08;聚…...

【Node.js】高级主题

个人主页&#xff1a;Guiat 归属专栏&#xff1a;node.js 文章目录 1. Node.js 高级主题概览1.1 高级主题架构图 2. 事件循环与异步编程深度解析2.1 事件循环机制详解事件循环阶段详解 2.2 异步编程模式演进高级异步模式实现 3. 内存管理与性能优化3.1 V8 内存管理机制内存监控…...

【Linux】定时任务 Crontab 与时间同步服务器

目录 一、用户定时任务的创建与使用 1.1 用户定时任务的使用技巧 1.2 管理员对用户定时任务的管理 1.3 用户黑白名单的管理 一、用户定时任务的创建与使用 1.1 用户定时任务的使用技巧 第一步&#xff1a;查看服务基本信息 systemctl status crond.service //查看周期性…...

【TCP/IP协议族详解】

目录 第1层 链路/网络接口层—帧&#xff08;Frame&#xff09; 1. 链路层功能 2. 常见协议 2.1. ARP&#xff08;地址解析协议&#xff09; 3. 常见设备 第2层 网络层—数据包&#xff08;Packet&#xff09; 1. 网络层功能 2. 常见协议 2.1. ICMP&#xff08;互联网…...

蓝桥杯电子赛_零基础利用按键实现不同数字的显现

目录 一、前提 二、代码配置 bsp_key.c文件 main.c文件 main.c文件的详细讲解 功能实现 注意事项 一、前提 按键这一板块主要是以记忆为主&#xff0c;我直接给大家讲解代码去实现我要配置的功能。本次我要做的项目是板子上的按键有S4~S19&#xff0c;我希望任意一个按键…...