欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > 鸿蒙学习手册(HarmonyOSNext_API16)_数据持久化③:关系型数据库

鸿蒙学习手册(HarmonyOSNext_API16)_数据持久化③:关系型数据库

2025/5/15 17:04:48 来源:https://blog.csdn.net/m0_71977266/article/details/146769372  浏览:    关键词:鸿蒙学习手册(HarmonyOSNext_API16)_数据持久化③:关系型数据库

概述

关系型数据库:像“Excel表格联合作战”的管家

关系型数据库就像一个超级智能的表格管理系统,专门处理数据之间有复杂关联的情况。比如学生和成绩、订单和商品、用户和评论——这些数据像蜘蛛网一样相互连接,用键值数据库的“独立抽屉”会手忙脚乱,而关系型数据库能像拼积木一样把它们严丝合缝地组装起来。


🌰 举个接地气的例子

场景1:班级学生管理系统

假设你是班主任,需要管理:

  1. 学生表(学号、姓名、性别)
  2. 课程表(课程编号、课程名称、任课老师)
  3. 成绩表(学号、课程编号、分数)

如果用键值数据库

  • 存储像这样👇(数据冗余且难关联):
    键: "学生_1001" → 值: {姓名:"张三", 性别:"男", 数学成绩:90, 英语老师:"王老师"}  
    键: "学生_1002" → 值: {姓名:"李四", 性别:"女", 数学成绩:85, 英语老师:"王老师"}  
    

问题:王老师改名时,需要遍历所有学生修改,效率极低。

用关系型数据库

  • 三张表互联,用“学号”“课程编号”作为桥梁:
    学生表课程表成绩表
    学号:1001 张三 男课程:C001 数学 张老师学号:1001 C001 90
    学号:1002 李四 女课程:C002 英语 王老师学号:1002 C001 85
  • 需要查“张三的数学成绩”时,只需一句SQL:
    SELECT 分数 FROM 成绩表  
    WHERE 学号=(SELECT 学号 FROM 学生表 WHERE 姓名='张三')  
    AND 课程编号=(SELECT 课程编号 FROM 课程表 WHERE 课程名称='数学');  
    

优势:改老师名字只需动课程表一处,所有关联数据自动生效。


场景2:电商订单系统

一个订单可能涉及:用户信息、商品详情、收货地址、支付记录。

  • 键值数据库的困局
    如果把整个订单存成一个Value:
    {  "订单号": "202310011234",  "用户": {"用户ID": 789, "姓名": "王五", "手机": "13800138000"},  "商品": [  {"商品ID": "G1001", "名称": "手机", "价格": 2999},  {"商品ID": "G1002", "名称": "耳机", "价格": 199}  ]  
    }  
    

痛点:想统计“所有买过手机的用户的手机号”,需要扫描所有订单,解析JSON,效率极低。

  • 关系型数据库的解法
    用户表商品表订单表订单详情表
    用户ID 姓名 手机商品ID 名称 价格订单ID 用户ID 总金额订单ID 商品ID 数量
  • 查“买过手机的用户的手机号”
    SELECT 用户表.手机  
    FROM 用户表  
    JOIN 订单表 ON 用户表.用户ID = 订单表.用户ID  
    JOIN 订单详情表 ON 订单表.订单ID = 订单详情表.订单ID  
    JOIN 商品表 ON 订单详情表.商品ID = 商品表.商品ID  
    WHERE 商品表.名称 = '手机';  
    

优势:像拼乐高一样关联多表,直接精准定位数据。


🤔 什么时候该用关系型数据库?

  1. 数据像家族族谱:需要理清“谁是谁的谁”(如用户→订单→商品)
  2. 经常要“跨界”查询:比如“统计每个班级的平均分,并显示班主任名字”
  3. 需要强一致性:比如转账操作(A账户减钱,B账户加钱必须同时成功)

⚠️ 什么时候别用它?

  1. 数据像散装沙子:比如独立缓存项(今日天气、临时验证码)
  2. 每秒要处理10万+请求:比如微博热搜实时计数(适合用Redis)
  3. 数据结构天天变:比如快速迭代中的实验性功能配置(适合用文档数据库如MongoDB)

现实中的工具

  • SQLite:手机APP本地存储(如微信聊天记录)、小型软件
  • MySQL:淘宝早期用户系统、知乎问答数据
  • PostgreSQL:苹果的iCloud部分服务、地理信息系统

// 导入关系型数据库模块和业务错误模块
import { relationalStore } from '@kit.ArkData';
import { BusinessError } from '@kit.BasicServicesKit';// 定义数据库配置
const STORE_CONFIG: relationalStore.StoreConfig = {name: 'RdbTest.db', // 数据库文件名securityLevel: relationalStore.SecurityLevel.S3, // 数据库安全级别encrypt: false, // 是否加密数据库,默认为不加密customDir: 'customDir/subCustomDir', // 自定义数据库路径(可选)isReadOnly: false // 是否以只读方式打开数据库,默认为可读写
};// 定义创建表的 SQL 语句
const SQL_CREATE_TABLE ='CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER, SALARY REAL, CODES BLOB, IDENTITY UNLIMITED INT)'; // 创建 EMPLOYEE 表// 定义插入数据的值
let value1 = 'Lisa';
let value2 = 18;
let value3 = 100.5;
let value4 = new Uint8Array([1, 2, 3, 4, 5]);
let value5 = BigInt('15822401018187971961171');let value6 = 'Rose';
let value7 = 22;
let value8 = 200.5;
let value9 = new Uint8Array([1, 2, 3, 4, 5]);
let value10 = BigInt('15822401018187971967863');// 定义插入的数据对象
const valueBucket1: relationalStore.ValuesBucket = {'NAME': value1,'AGE': value2,'SALARY': value3,'CODES': value4,'IDENTITY': value5,
};const valueBucket5: relationalStore.ValuesBucket = {NAME: value6,AGE: value7,SALARY: value8,CODES: value9,IDENTITY: value10,
};// 定义组件结构
@Entry
@Component
struct RdbStore {context = getContext(this); // 获取上下文store: relationalStore.RdbStore | undefined = undefined; // 数据库实例/*** 插入数据到数据库*/async rdbInsert() {if (this.store !== undefined) {await (this.store as relationalStore.RdbStore).insert('EMPLOYEE', valueBucket1, (err: BusinessError, rowId: number) => {if (err) {console.error(`Failed to insert data. Code:${err.code}, message:${err.message}`); // 插入失败时的日志return;}console.log(`Succeeded in inserting data. rowId:${rowId}`); // 插入成功时的日志});console.log('rdbInsert'); // 调试日志}}/*** 更新数据库中的数据*/async rdbUpdate() {let predicates1 = new relationalStore.RdbPredicates('EMPLOYEE'); // 创建查询条件predicates1.equalTo('NAME', 'Lisa'); // 匹配 NAME 为 'Lisa' 的记录if (this.store !== undefined) {await (this.store as relationalStore.RdbStore).update(valueBucket5, predicates1, (err: BusinessError, rows: number) => {if (err) {console.error(`Failed to update data. Code:${err.code}, message:${err.message}`); // 更新失败时的日志return;}console.log(`Succeeded in updating data. row count: ${rows}`); // 更新成功时的日志});console.log('rdbUpdate'); // 调试日志}}/*** 删除数据库中的数据*/async rdbDelete() {let predicates1 = new relationalStore.RdbPredicates('EMPLOYEE'); // 创建查询条件predicates1.equalTo('NAME', 'Lisa'); // 匹配 NAME 为 'Lisa' 的记录if (this.store !== undefined) {await (this.store as relationalStore.RdbStore).delete(predicates1, (err: BusinessError, rows: number) => {if (err) {console.error(`Failed to delete data. Code:${err.code}, message:${err.message}`); // 删除失败时的日志return;}console.log(`Delete rows: ${rows}`); // 删除成功时的日志});console.log('rdbDelete'); // 调试日志}}/*** 查询数据库中的数据*/async rdbQuery() {let predicates2 = new relationalStore.RdbPredicates('EMPLOYEE'); // 创建查询条件predicates2.equalTo('NAME', 'Lisa'); // 匹配 NAME 为 'Lisa' 的记录if (this.store !== undefined) {await (this.store as relationalStore.RdbStore).query(predicates2, ['ID', 'NAME', 'AGE', 'SALARY', 'IDENTITY'], (err: BusinessError, resultSet) => {if (err) {console.error(`Failed to query data. Code:${err.code}, message:${err.message}`); // 查询失败时的日志return;}console.info(`ResultSet column names: ${resultSet.columnNames}, column count: ${resultSet.columnCount}`); // 查询结果信息while (resultSet.goToNextRow()) { // 遍历查询结果const id = resultSet.getLong(resultSet.getColumnIndex('ID'));const name = resultSet.getString(resultSet.getColumnIndex('NAME'));const age = resultSet.getLong(resultSet.getColumnIndex('AGE'));const salary = resultSet.getDouble(resultSet.getColumnIndex('SALARY'));const identity = resultSet.getValue(resultSet.getColumnIndex('IDENTITY'));console.log(`id=${id}, name=${name}, age=${age}, salary=${salary}, identity=${identity}`); // 输出每条记录的信息}resultSet.close(); // 关闭结果集});console.log('rdbQuery'); // 调试日志}}/*** 获取数据库实例*/async getRdbStore() {console.log('getRdbStore'); // 调试日志await relationalStore.getRdbStore(this.context, STORE_CONFIG, (err, store) => {if (err) {console.error(`Failed to get RdbStore. Code:${err.code}, message:${err.message}`); // 获取数据库失败时的日志return;}console.info('Succeeded in getting RdbStore.'); // 获取数据库成功时的日志store.executeSql(SQL_CREATE_TABLE); // 执行建表语句this.store = store; // 将数据库实例赋值给成员变量});}/*** 页面即将消失时关闭数据库*/async aboutToDisappear() {if (this.store !== undefined) {await this.store.close(); // 关闭数据库}}/*** 页面即将出现时初始化数据库*/async aboutToAppear() {await this.getRdbStore(); // 初始化数据库}/*** 构建页面布局*/build() {Column() {Button("添加数据") // 添加数据按钮.onClick(() => {this.rdbInsert(); // 调用插入方法}).width('100%').margin({ top: 10 });Button("查询数据") // 查询数据按钮.onClick(async () => {this.rdbQuery(); // 调用查询方法}).width('100%').margin({ top: 10 });Button("修改数据") // 修改数据按钮.onClick(async () => {this.rdbUpdate(); // 调用更新方法}).width('100%').margin({ top: 10 });Button("删除数据") // 删除数据按钮.onClick(async () => {this.rdbDelete(); // 调用删除方法}).width('100%').margin({ top: 10 });}.width('100%'); // 设置列宽为 100%}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词