【HarmonyOS Relational Database】鸿蒙关系型数据库

基本介绍

在鸿蒙系统中,relationalStore 是 ArkTS 提供的关系型数据库模块,用于管理本地结构化数据。它支持 SQL 查询、事务处理、条件查询等常见数据库操作,适用于需要持久化存储结构化数据的场景。

  • 包路径:@kit.ArkData
  • 核心类:
    • relationalStore.getRdbStore():获取或创建一个数据库实例
    • relationalStore.RdbStore:表示一个具体的数据库对象
    • relationalStore.RdbPredicates:构建查询/更新/删除条件语句
    • relationalStore.ResultSet:封装查询结果集

代码实现

typescript 复制代码
import { relationalStore } from '@kit.ArkData'
import { CONTEXT } from '../constants'

// 录音数据类型
export interface InterviewAudioItem extends relationalStore.ValuesBucket {
  id: number | null
  user_id: string
  name: string
  path: string
  duration: number
  size: number
  create_time: number
}

class AudioDB {
  store?: relationalStore.RdbStore
  tableName: string = 'interview_audio'

  /**
   * 初始化数据库和建表
   */
  async initStore() {
    const ctx = AppStorage.get<Context>(CONTEXT)
    if (ctx) {
      const store = await relationalStore.getRdbStore(ctx, {
        name: 'interview_tong.db',
        securityLevel: relationalStore.SecurityLevel.S1
      })
      const sql = `
        CREATE TABLE IF NOT EXISTS ${this.tableName} (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          user_id TEXT NOT NULL,
          name TEXT NOT NULL,
          path TEXT NOT NULL,
          duration INTEGER NOT NULL,
          size INTEGER NOT NULL,
          create_time INTEGER NOT NULL
        )
      `
      await store.executeSql(sql)
      // 记录数据库实例
      this.store = store
    }
  }

  /**
   * 添加
   * @param interviewAudioItem 录音信息对象
   * @returns Promise<void>
   */
  async insert(interviewAudioItem: InterviewAudioItem) {
    // rowId 是插入成功的行ID,-1 代表失败
    const rowId = await this.store?.insert(this.tableName, interviewAudioItem)
    if (rowId === undefined || rowId === -1) {
      return Promise.reject('insert fail')
    } else {
      return Promise.resolve()
    }
  }

  /**
   * 删除
   * @param id 录音数据的ID
   * @returns Promise<void>
   */
  async delete(id: number) {
    const predicates = new relationalStore.RdbPredicates(this.tableName)
    predicates.equalTo('id', id)
    // rowCount 是删除影响的行数,删除了多少条
    const rowCount = await this.store?.delete(predicates)
    if (rowCount === undefined || rowCount <= 0) {
      return Promise.reject('delete fail')
    } else {
      return Promise.resolve()
    }
  }

  /**
   * 修改
   * @param interviewAudioItem 录音信息对象
   * @returns Promise<void>
   */
  async update(interviewAudioItem: InterviewAudioItem) {
    const predicates = new relationalStore.RdbPredicates(this.tableName)
    predicates.equalTo('id', interviewAudioItem.id)
    // rowCount 是修改影响的行数
    const rowCount = await this.store?.update(interviewAudioItem, predicates)
    if (rowCount === undefined || rowCount <= 0) {
      return Promise.reject('update fail')
    } else {
      return Promise.resolve()
    }
  }

  /**
   * 查询用户的录音
   * @param userId
   * @returns Promise<InterviewAudioItem[]>
   */
  async query(userId: string) {
    const predicates = new relationalStore.RdbPredicates(this.tableName)
    // 查询当前用户下的录音信息
    predicates.equalTo('user_id', userId)
    const resultSet = await this.store?.query(predicates)
    // 没有结果查询失败
    if (!resultSet) {
      return Promise.reject('query fail')
    }
    const list: InterviewAudioItem[] = []
    while (resultSet.goToNextRow()) {
      list.push({
        id: resultSet.getLong(resultSet.getColumnIndex('id')),
        user_id: resultSet.getString(resultSet.getColumnIndex('user_id')),
        name: resultSet.getString(resultSet.getColumnIndex('name')),
        path: resultSet.getString(resultSet.getColumnIndex('path')),
        duration: resultSet.getLong(resultSet.getColumnIndex('duration')),
        size: resultSet.getLong(resultSet.getColumnIndex('size')),
        create_time: resultSet.getLong(resultSet.getColumnIndex('create_time'))
      })
    }
    resultSet.close()
    return Promise.resolve(list)
  }
}


export const audioDB = new AudioDB()

结构说明

1. 数据表定义与初始化

表名

ts 复制代码
tableName: string = 'interview_audio'

字段定义(见 InterviewAudioItem 接口)

字段名 类型 约束 描述
id INTEGER PRIMARY KEY AUTOINCREMENT 主键,自增
user_id TEXT NOT NULL 用户ID
name TEXT NOT NULL 录音名称
path TEXT NOT NULL 文件路径
duration INTEGER NOT NULL 时长(毫秒)
size INTEGER NOT NULL 文件大小(字节)
create_time INTEGER NOT NULL 创建时间戳(毫秒)

初始化数据库与建表

ts 复制代码
async initStore()
  • 使用 relationalStore.getRdbStore() 获取或创建数据库文件 interview_tong.db
  • 设置安全等级为 S1
  • 执行建表 SQL 语句(若表不存在)
  • 将数据库实例保存到 this.store 中供后续使用

2. 数据库操作方法详解

✅ 插入数据:insert(interviewAudioItem: InterviewAudioItem)

  • 使用 store.insert(table, values) 方法插入一条记录
  • 返回值:
    • 成功:Promise.resolve()
    • 失败:Promise.reject('insert fail')
  • 注意事项:
    • interviewAudioItem 必须符合 ValuesBucket 结构(键值对形式)

❌ 删除数据:delete(id: number)

  • 构造 RdbPredicates 条件:id = ?
  • 调用 store.delete(predicates) 删除符合条件的数据
  • 返回值:
    • 成功:Promise.resolve()
    • 失败:Promise.reject('delete fail')

🔁 更新数据:update(interviewAudioItem: InterviewAudioItem)

  • 构造 RdbPredicates 条件:id = interviewAudioItem.id
  • 调用 store.update(values, predicates) 更新指定字段
  • 返回值:
    • 成功:Promise.resolve()
    • 失败:Promise.reject('update fail')

🔍 查询数据:query(userId: string)

  • 构造 RdbPredicates 条件:user_id = userId
  • 调用 store.query(predicates) 查询数据,返回 ResultSet
  • 遍历 ResultSet 并将每条记录转换为 InterviewAudioItem 对象
  • 最终返回 Promise<InterviewAudioItem[]>
  • 注意事项:
    • 使用完 ResultSet 后必须调用 .close() 关闭资源

使用建议与注意事项

✅ 建议

  • 所有数据库操作应放在异步函数中执行(已实现)
  • 使用 RdbPredicates 可以避免手动拼接 SQL 语句,提高安全性
  • query() 中关闭 ResultSet 是良好习惯,防止内存泄漏

⚠️ 注意

  • store 可能为 undefined,因此每次操作都应加可选链判断(如 this.store?.insert(...)
  • AppStorage.get<Context>(CONTEXT) 必须正确配置上下文环境
  • 表名、字段名尽量统一命名规范,避免 SQL 注入风险

总结

AudioDB 类是一个完整的数据库访问层(DAO),封装了录音数据的 CRUD 操作,并通过 ArkTS 的 relationalStore 模块实现了鸿蒙平台上的本地持久化能力。整体结构清晰,逻辑合理,适合用于 HarmonyOS 应用中的录音信息管理模块。

相关推荐
早點睡3902 分钟前
高级进阶 ReactNative for Harmony 项目鸿蒙化三方库集成实战:react-native-video
react native·华为·harmonyos
开开心心就好6 分钟前
发票合并打印工具,多页布局设置实时预览
linux·运维·服务器·windows·pdf·harmonyos·1024程序员节
前端不太难1 小时前
HarmonyOS 游戏项目,从 Demo 到可上线要跨过哪些坑
游戏·状态模式·harmonyos
全栈探索者1 小时前
列表渲染不用 map,用 ForEach!—— React 开发者的鸿蒙入门指南(第 4 期)
react.js·harmonyos·arkts·foreach·列表渲染
一只大侠的侠2 小时前
Flutter开源鸿蒙跨平台训练营 Day8获取轮播图网络数据并实现展示
flutter·开源·harmonyos
Lionel6893 小时前
鸿蒙Flutter跨平台开发:首页特惠推荐模块的实现
华为·harmonyos
盐焗西兰花4 小时前
鸿蒙学习实战之路-Reader Kit自定义页面背景最佳实践
学习·华为·harmonyos
果粒蹬i4 小时前
【HarmonyOS】DAY10:React Native开发应用品质升级:响应式布局与用户体验优化实践
华为·harmonyos·ux
早點睡3904 小时前
基础入门 React Native 鸿蒙跨平台开发:react-native-flash-message 消息提示三方库适配
react native·react.js·harmonyos
早點睡3905 小时前
高级进阶 ReactNative for Harmony项目鸿蒙化三方库集成实战:react-native-image-picker(打开手机相册)
react native·react.js·harmonyos