鸿蒙RDB数据库封装与使用实践

最近项目又要搞数据存储,鸿蒙的RDB用起来还挺啰嗦,干脆自己封装了个工具类,省得每次都写一堆重复代码。这里随手记下,万一以后自己忘了还能翻出来看看。

一、SQL基础知识

1.1 什么是SQL

SQL(Structured Query Language)是用来操作关系型数据库的标准语言。其实最常用的就那几句,真遇到复杂的,百度/ChatGPT一搜一大把。

1.2 常用SQL语句

  1. 创建表
CREATE TABLE user_info (
id INTEGER PRIMARY KEY AUTOINCREMENT, -- 主键,自增
name TEXT, -- 文本类型
age INTEGER, -- 整数类型
score REAL, -- 浮点类型
is_active INTEGER DEFAULT 0 -- 默认值
);
  1. 插入数据
INSERT INTO user_info (name, age) VALUES ('张三', 18);
  1. 查询数据
-- 查询所有字段
SELECT * FROM user_info; -- 条件查询
SELECT name, age FROM user_info WHERE age > 18; -- 排序
SELECT * FROM user_info ORDER BY age DESC; -- 限制数量
SELECT * FROM user_info LIMIT 10;
  1. 更新数据
UPDATE user_info SET age = 20 WHERE name = '张三';
  1. 删除数据
DELETE FROM user_info WHERE age < 18;

二、开发背景

其实一开始我没打算封装,结果每次用都得写一堆初始化、建表、try-catch,烦得很。后来干脆写了个RDBUtils,省心多了。

三、实现步骤

3.1 创建RDB工具类

import relationalStore from '@ohos.data.relationalStore';
import common from '@ohos.app.ability.common'; // 数据库配置
const STORE_CONFIG: relationalStore.StoreConfig = {
name: 'user.db',
securityLevel: relationalStore.SecurityLevel.S1
}; // 数据库版本号
const DB_VERSION = 2; // 创建表的SQL语句
const SQL_CREATE_TABLE = `
CREATE TABLE IF NOT EXISTS user_info (
id INTEGER PRIMARY KEY AUTOINCREMENT,
avatarUri TEXT,
nickName TEXT,
unionID TEXT,
openID TEXT,
authorizationCode TEXT,
createTime INTEGER,
memo TEXT,
isSynced INTEGER DEFAULT 0
)
`; export class RDBUtils {
private static instance: RDBUtils | null = null;
private rdbStore: relationalStore.RdbStore | null = null;
private context: common.Context; // 单例模式
public static getInstance(context: common.Context): RDBUtils {
if (!RDBUtils.instance) {
RDBUtils.instance = new RDBUtils(context);
}
return RDBUtils.instance;
} // 初始化数据库
async initRDB(): Promise<void> {
if (this.rdbStore) {
return;
} try {
this.rdbStore = await relationalStore.getRdbStore(this.context, STORE_CONFIG);
await this.rdbStore.executeSql(SQL_CREATE_TABLE);
await this.checkAndUpdateVersion();
} catch (err) {
console.error(`初始化数据库失败: ${err}`);
throw err;
}
} // 数据库升级
private async checkAndUpdateVersion(): Promise<void> {
// 检查版本并执行升级
const currentVersion = await this.getCurrentVersion();
if (currentVersion < DB_VERSION) {
await this.upgradeDatabase(currentVersion);
}
}
}

3.2 实现CRUD操作

export class RDBUtils {
// ... 前面的代码 ... // 插入数据
async insertUser(user: UserInfo): Promise<number> {
if (!this.rdbStore) {
throw new Error('数据库未初始化');
} const valueBucket: relationalStore.ValuesBucket = {
'avatarUri': user.avatarUri || '',
'nickName': user.nickName || '',
'unionID': user.unionID || '',
'openID': user.openID || '',
'authorizationCode': user.authorizationCode || '',
'createTime': user.createTime || Date.now(),
'memo': user.memo || '',
'isSynced': user.isSynced ? 1 : 0
}; try {
return await this.rdbStore.insert('user_info', valueBucket);
} catch (err) {
console.error(`插入数据失败: ${err}`);
throw err;
}
} // 更新数据
async updateUser(user: UserInfo): Promise<number> {
if (!this.rdbStore || !user.id) {
throw new Error('参数错误');
} const valueBucket: relationalStore.ValuesBucket = {
'avatarUri': user.avatarUri || '',
'nickName': user.nickName || '',
// ... 其他字段
}; const predicates = new relationalStore.RdbPredicates('user_info');
predicates.equalTo('id', user.id); try {
return await this.rdbStore.update(valueBucket, predicates);
} catch (err) {
console.error(`更新数据失败: ${err}`);
throw err;
}
} // 查询数据
async queryUserById(id: number): Promise<UserInfo | null> {
if (!this.rdbStore) {
throw new Error('数据库未初始化');
} const predicates = new relationalStore.RdbPredicates('user_info');
predicates.equalTo('id', id); try {
const resultSet = await this.rdbStore.query(predicates, ['*']);
if (resultSet.goToNextRow()) {
const user = this.parseUserFromResultSet(resultSet);
resultSet.close();
return user;
}
resultSet.close();
return null;
} catch (err) {
console.error(`查询数据失败: ${err}`);
throw err;
}
}
}

四、踩坑记录

  • 单例不做,内存飙升,手机直接卡死,血的教训。
  • 查询结果集忘记close,内存泄漏,调了半天才发现。
  • 批量插入不加事务,慢得想砸电脑。
  • 插入数据时没处理空值,数据库直接报错。
  • 更新数据时没检查ID,更新失败,debug半天。

五、使用示例

比如我有个用户表,插入、查、改、删都靠这套,写起来就几行代码,舒服。

// 初始化数据库
const rdbUtils = RDBUtils.getInstance(context);
await rdbUtils.initRDB(); // 插入数据
const user: UserInfo = {
avatarUri: 'https://example.com/avatar.jpg',
nickName: '张三',
unionID: '123456',
openID: '789012',
authorizationCode: 'abc123'
};
const id = await rdbUtils.insertUser(user); // 查询数据
const user = await rdbUtils.queryUserById(id);
console.info(`查询到用户: ${user?.nickName}`); // 更新数据
if (user) {
user.nickName = '李四';
await rdbUtils.updateUser(user);
} // 删除数据
await rdbUtils.deleteUser(id);

六、注意事项

  • 千万别忘了异常处理,出错了不提示,用户一脸懵。
  • 结果集不用就close,不然你会怀疑人生。
  • 数据类型别写错,调试起来很费劲。
  • 合理用索引,批量操作记得加事务。
  • 敏感数据要加密,别让用户数据裸奔。

七、总结

反正这玩意我自己用着还挺顺手,大家有更好的写法欢迎留言交流,别让我一个人踩坑。

八、参考资源

欢迎体验

这个RDB工具类已经集成到鸿蒙开发者工具箱里了,欢迎下载体验!

鸿蒙开发者工具箱


作者:在人间耕耘

邮箱:1743914721@qq.com

版权声明:本文为博主原创文章,转载请附上原文出处链接及本声明。

开发者工具箱-鸿蒙RDB数据库封装与使用实践的更多相关文章

  1. mysql数据库封装和 分页查询

    1 之前我们学到了php连接mysql数据库的增删改查,中间要多次调用数据库, 而且以后用到的表比较多,上传中如果需要改数据的话会非常麻烦,但是如果 我们把数据库封装,到时就可以很轻松的把改掉一些数据 ...

  2. Asp.Net Core 2.0 项目实战(4)ADO.NET操作数据库封装、 EF Core操作及实例

    Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了 Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架 Asp.Ne ...

  3. MySQL数据库封装和分页查询

    1.数据库封装 <?php //我用的数据库名是housedb class DBDA {public $host="localhost";public $uid=" ...

  4. 【Cocos2d-x Lua】数据库封装类型的操作

    Lua数据库封装类型的操作 使用演示样例 lua代码: require("DB") -- 保存一个字符串(数据库中存储的数据都是以字符串的形式保存的) DB:getInstance ...

  5. 数据库周刊28│开发者最喜爱的数据库是什么?阿里云脱口秀聊程序员转型;MySQL update误操作;PG流复制踩坑;PG异机归档;MySQL架构选型;Oracle技能表;Oracle文件损坏处理……

    热门资讯 1.Stackoverflow 2020年度报告出炉!开发者最喜爱的数据库是什么?[摘要]2020年2月,近6.5万名开发者参与了 Stackoverflow 的 2020 年度调查,这份报 ...

  6. XPages访问关系型数据库技术与最佳实践

    XPage 对于 Domino 开发人员的一大好处就是能够很方便和高效的访问关系型数据库.本文通过实例代码展现了在 XPage 中访问关系型数据库的具体步骤 , 同时讲解了一些在 XPage 中高效访 ...

  7. Cobar分布式数据库的应用与实践

    最新文章:看我如何快速学习.Net(高可用数据采集平台).高并发数据采集的架构应用(Redis的应用) 问题点: 随着项目的增长,数据和数据表也成倍的增长,普通的单点数据库已经无法满足日常的增长的需要 ...

  8. 单KEY业务,数据库水平切分架构实践 | 架构师之路

    https://mp.weixin.qq.com/s/8aI9jS0SXJl5NdcM3TPYuQ 单KEY业务,数据库水平切分架构实践 | 架构师之路 原创: 58沈剑 架构师之路 2017-06- ...

  9. 单机数据库优化的一些实践(mysql)

    数据库优化有很多可以讲,按照支撑的数据量来分可以分为两个阶段:单机数据库和分库分表,前者一般可以支撑500W或者10G以内的数据,超过这个值则需要考虑分库分表.另外,一般大企业面试往往会从单机数据库问 ...

  10. mysql数据库封装

    <?php /** * name: sql操作封装,可扩展 . * User: 张云山 * Date: 2016/9/4 * Time: 22:02 */ //php文件编码设置header(' ...

随机推荐

  1. Pydantic递归模型深度校验36计:从无限嵌套到亿级数据的优化法则

    title: Pydantic递归模型深度校验36计:从无限嵌套到亿级数据的优化法则 date: 2025/3/26 updated: 2025/3/26 author: cmdragon excer ...

  2. 【C#】SuperSocket配置启动UDP服务器

    SuperSocket配置UDP服务器 零.需求 两个设备局域网联机,需要用广播自动搜寻,而SuperSocket1.6的默认AppServer使用的是TCP,但只有UDP才支持广播. 一.解决 推荐 ...

  3. Oracle 归档模式

    sqlplus / as sysdba # 以下操作在`sqlplus`中执行 查看日志模式 SQL> archive log list; 数据库日志模式 非存档模式 自动存档 禁用 存档终点 ...

  4. Docker Commonds

    脑子不够用,记录下自己所学所用的命令,备忘...不断补充. 最最基本的命令 查看 docker 信息 docker info 查看 docker 版本及相关信息 docker version 仅查看 ...

  5. 学习unigui【21】unistringGrid的标题栏动态增加

    var Column: TUniGridColumn; begin Column := TUniGridColumn(unstrngrd_summary.Columns.Add); Column.Ti ...

  6. study Rust-1【Rust的特点和应用场景】

    Rust语言的特点 高性能 - Rust 速度惊人且内存利用率极高.由于没有运行时和垃圾回收,它能够胜任对性能要求特别高的服务,可以在嵌入式设备上运行,还能轻松和其他语言集成. 可靠性 - Rust ...

  7. SRE网站可靠性工程师

    SRE网站可靠性工程师 SRE需要做什么? 一般: 故障模式,尤其是SPOF(单点故障).消除SPOFs是你作为SRE最大的挑战和乐趣. 基础设施组件,从应用程序到硬件(服务器.交换机.路由器.互联网 ...

  8. SQLAlchemy 核心概念与同步引擎配置详解

    title: SQLAlchemy 核心概念与同步引擎配置详解 date: 2025/04/14 00:28:46 updated: 2025/04/14 00:28:46 author: cmdra ...

  9. STM32真的是很落后吗?

    STM32真的是很落后吗? 作为一名嵌入式开发老兵,我不止一次听到有人说"STM32已经过时了",尤其是那些刚入门或者看了几篇文章的新手.每当听到这样的言论,我都忍不住想笑,但又有 ...

  10. app自动化:Androiddriver操作api

    一.获取操作的api 1.currentActivity():获取当前activity 一般获取到当前activity与预期进行断言 androidDriver.currentActivity(); ...