基本介绍
在鸿蒙系统中,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 应用中的录音信息管理模块。