HarmonyOS 鸿蒙Next中关系数据库使用
HarmonyOS 鸿蒙Next中关系数据库使用 一下午捣鼓了一下数据存储,目前是给TODO应用写了一个数据库工具,感觉是比较麻烦,不过也正常,但是就是希望可以多学习一些技巧和方法,帮助管理数据,因为之前就只搞过简单数据库,有点吃不下,请不吝赐教。
首先是看一下需要用到的接口:
// 用户创建的表
export interface ListTmp
{
title: string, // 列表的名字
// ...
}
// 枚举状态
export enum ItemStatus
{
Finish, // 完成
Overdue, // 逾期
// ...
}
// 一条一条的todo项目
export interface TodoTmp
{
title: string, // 条目的标题
content: string, // 条目的内容
TAG: string[], // 条目所属的tag
isDone: boolean, // 完成状态
status: ItemStatus,
start: Date, // 起始时间
deadLine: Date, // 结束时间
// ...
}
然后就是具体数据库的工具:
//Util.ets
import { relationalStore } from '@kit.ArkData'
import { hilog } from '@kit.PerformanceAnalysisKit'
import { BusinessError } from '@kit.BasicServicesKit'
import { ListTmp, TodoTmp, ItemStatus } from '../model/AllInterface'
const TAG: string = 'RDBStoreUtil'
export class RDBStoreUtil
{
objectiveRDB?: relationalStore.RdbStore
createObjectiveRDB(context: Context)
{
const STORE_CONFIG: relationalStore.StoreConfig = {
name: 'Objective.db',
securityLevel: relationalStore.SecurityLevel.S1,
}
relationalStore.getRdbStore(context, STORE_CONFIG, (err: BusinessError, rdbStore: relationalStore.RdbStore) => {
if (err)
{
hilog.error(0x0000, TAG, `Get RdbStore failed, code is ${err.code},message is ${err.message}`)
return
}
this.objectiveRDB = rdbStore;
hilog.info(0x0000, TAG, 'Get RdbStore successfully.')
this.createListTable();
this.createTodoTable();
})
}
/**
* 创建「列表」表(对应ListTmp接口)
*/
createListTable()
{
const createListSql = `
CREATE TABLE IF NOT EXISTS LISTS (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL -- 列表名称(对应ListTmp.title)
)
`
this.objectiveRDB?.execute(createListSql)
.then(() => hilog.info(0x0000, TAG, `Create lists table success`))
.catch((err: BusinessError) =>
hilog.error(0x0000, TAG, `Create lists table failed: ${err.code} - ${err.message}`)
)
}
/**
* 创建「待办项」表(对应TodoItem接口)
*/
createTodoTable()
{
const createTodoSql = `
CREATE TABLE IF NOT EXISTS TODOS (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL, -- 条目标题(对应TodoItem.title)
content TEXT NOT NULL, -- 条目内容(对应TodoItem.content)
tag TEXT NOT NULL, -- 标签数组(存JSON字符串,对应TodoItem.TAG)
is_done INTEGER NOT NULL, -- 完成状态(0=false/1=true,对应TodoItem.isDone)
status TEXT NOT NULL, -- 状态枚举(存字符串值,对应TodoItem.status)
start TEXT NOT NULL, -- 开始时间(ISO字符串,对应TodoItem.start)
deadline TEXT NOT NULL -- 截止时间(ISO字符串,对应TodoItem.deadLine)
)
`
this.objectiveRDB?.execute(createTodoSql)
.then(() => hilog.info(0x0000, TAG, `Create todos table success`))
.catch((err: BusinessError) =>
hilog.error(0x0000, TAG, `Create todos table failed: ${err.code} - ${err.message}`)
)
}
/**
* 插入一个列表
*/
async insertList(listItem: ListTmp)
{
const listData: relationalStore.ValuesBucket = {
'title': listItem.title
}
await this.objectiveRDB?.insert('LISTS', listData,
relationalStore.ConflictResolution.ON_CONFLICT_REPLACE).then((rowId: number) => {
hilog.info(0x0000, TAG, `Insert is successful, rowId = ${rowId}`);
}).catch((err: BusinessError) => {
hilog.error(0x0000, TAG, `Insert is failed, code is ${err.code},message is ${err.message}`);
})
}
/**
* 插入一个待办事项
*/
async insertTodo(todoItem: TodoTmp)
{
const todoData: relationalStore.ValuesBucket = {
'title': todoItem.title,
'content': todoItem.content,
'tag': todoItem.TAG.toString(),
'is_done': todoItem.isDone,
'status': todoItem.status,
'start': todoItem.start.toString(),
'deadline': todoItem.deadLine.toString()
}
await this.objectiveRDB?.insert('TODOS', todoData,
relationalStore.ConflictResolution.ON_CONFLICT_REPLACE).then((rowId: number) => {
hilog.info(0x0000, TAG, `Insert is successful, rowId = ${rowId}`);
}).catch((err: BusinessError) => {
hilog.error(0x0000, TAG, `Insert is failed, code is ${err.code},message is ${err.message}`);
})
}
/**
* 查询所有列表
*/
async queryAllLists(): Promise<ListTmp[]>
{
let listsSet: Array<ListTmp> = []
await this.objectiveRDB?.querySql(
`SELECT title FROM LISTS`
)
.then((resultSet: relationalStore.ResultSet) => {
while (resultSet.goToNextRow())
{
const id = resultSet.getValue(resultSet.getColumnIndex('ID')) as number
const title = resultSet.getValue(resultSet.getColumnIndex('title')) as string;
}
resultSet.close();
}).catch((err: BusinessError) => {
hilog.error(0x0000, TAG, `Query failed, code is ${err.code},message is ${err.message}`)
})
return listsSet;
}
/**
* 查询所有待办
*/
async queryAllTodos(): Promise<TodoTmp[]>
{
let todosSet: Array<TodoTmp> = []
await this.objectiveRDB?.querySql(
`SELECT title, content, tag, is_done, status, start, deadline FROM TODOS`
)
.then((resultSet: relationalStore.ResultSet) => {
while (resultSet.goToNextRow())
{
const id = resultSet.getValue(resultSet.getColumnIndex('ID')) as number
const title = resultSet.getValue(resultSet.getColumnIndex('title')) as string
const content = resultSet.getValue(resultSet.getColumnIndex('content')) as string
const tagStr = resultSet.getValue(resultSet.getColumnIndex('tag')) as string;
let tag: string[] = [];
try
{
tag = JSON.parse(tagStr) as string[]; // 反向解析插入时的JSON字符串
}
catch (err)
{
hilog.error(0x0000, TAG, `Parse tag failed for todo ${id}: ${(err as Error).message}`);
}
const isDone = Boolean(resultSet.getValue(resultSet.getColumnIndex('is_done')) as number);
const status = resultSet.getValue(resultSet.getColumnIndex('status')) as ItemStatus;
const start = resultSet.getValue(resultSet.getColumnIndex('start')) as string;
const deadLine = resultSet.getValue(resultSet.getColumnIndex('deadline')) as string;
}
resultSet.close();
}).catch((err: BusinessError) => {
hilog.error(0x0000, TAG, `Query failed, code is ${err.code},message is ${err.message}`)
})
return todosSet
}
// ========================================
// 【新增】更新列表(匹配示例风格)
// ========================================
/**
* The method of updating a list information.
* @param listID 列表主键ID
* @param listItem 待更新的列表信息
*/
async updateList(listID: number, listItem: ListTmp)
{
if (!this.objectiveRDB)
{
const errMsg = 'RDBStore未初始化,无法更新列表'
hilog.error(0x0000, TAG, errMsg)
throw new Error(errMsg)
}
// 1. 构建更新字段(ListTmp仅含title)
const listData: relationalStore.ValuesBucket = {
'title': listItem.title
}
// 2. 构建条件:通过ID定位
const predicates = new relationalStore.RdbPredicates('LISTS')
predicates.equalTo('ID', listID)
// 3. 执行更新
await this.objectiveRDB.update(
listData,
predicates,
relationalStore.ConflictResolution.ON_CONFLICT_REPLACE
).then(async (rows: Number) => {
hilog.info(0x0000, TAG, `Updated list row count: ${rows}`)
}).catch((err: BusinessError) => {
hilog.error(0x0000, TAG, `Update list failed, code is ${err.code}, message is ${err.message}`)
})
}
// ========================================
// 【新增】更新待办(匹配示例风格 + 字段转换)
// ========================================
/**
* The method of updating a todo information.
* @param todoID 待办主键ID
* @param todoItem 待更新的待办信息
*/
async updateTodo(todoID: number, todoItem: TodoTmp)
{
if (!this.objectiveRDB)
{
const errMsg = 'RDBStore未初始化,无法更新待办'
hilog.error(0x0000, TAG, errMsg)
throw new Error(errMsg)
}
// 1. 构建更新字段(处理数组/布尔/时间格式)
const todoData: relationalStore.ValuesBucket = {
'title': todoItem.title,
'content': todoItem.content,
'tag': JSON.stringify(todoItem.TAG), // 数组转JSON字符串
'is_done': todoItem.isDone ? 1 : 0, // 布尔值转数字
'status': todoItem.status,
'start': todoItem.start.toISOString(), // 时间转ISO格式
'deadline': todoItem.deadLine.toISOString() // 时间转ISO格式
}
// 2. 构建条件:通过ID定位
const predicates = new relationalStore.RdbPredicates('TODOS')
predicates.equalTo('ID', todoID)
// 3. 执行更新
await this.objectiveRDB.update(
todoData,
predicates,
relationalStore.ConflictResolution.ON_CONFLICT_REPLACE
).then(async (rows: Number) => {
hilog.info(0x0000, TAG, `Updated todo row count: ${rows}`)
}).catch((err: BusinessError) => {
hilog.error(0x0000, TAG, `Update todo failed, code is ${err.code}, message is ${err.message}`)
})
}
// ========================================
// 【新增】删除列表(匹配示例风格)
// ========================================
/**
* The method of deleting a list information.
* @param listID 列表主键ID
*/
async deleteList(listID: number)
{
if (!this.objectiveRDB)
{
const errMsg = 'RDBStore未初始化,无法删除列表'
hilog.error(0x0000, TAG, errMsg)
throw new Error(errMsg)
}
// 1. 构建条件:通过ID定位
const predicates = new relationalStore.RdbPredicates('LISTS')
predicates.equalTo('ID', listID)
// 2. 执行删除
await this.objectiveRDB.delete(predicates)
.then((rows: Number) => {
hilog.info(0x0000, TAG, `Delete list row count: ${rows}`)
}).catch((err: BusinessError) => {
hilog.error(0x0000, TAG, `Delete list failed, code is ${err.code}, message is ${err.message}`)
})
}
// ========================================
// 【新增】删除待办(匹配示例风格)
// ========================================
/**
* The method of deleting a todo information.
* @param todoID 待办主键ID
*/
async deleteTodo(todoID: number)
{
if (!this.objectiveRDB)
{
const errMsg = 'RDBStore未初始化,无法删除待办'
hilog.error(0x0000, TAG, errMsg)
throw new Error(errMsg)
}
// 1. 构建条件:通过ID定位
const predicates = new relationalStore.RdbPredicates('TODOS')
predicates.equalTo('ID', todoID)
// 2. 执行删除
await this.objectiveRDB.delete(predicates)
.then((rows: Number) => {
hilog.info(0x0000, TAG, `Delete todo row count: ${rows}`)
}).catch((err: BusinessError) => {
hilog.error(0x0000, TAG, `Delete todo failed, code is ${err.code}, message is ${err.message}`)
})
}
}
export default new RDBStoreUtil();
感觉写的比较冗余(shit mountain),也担心会有数据隐患,很怕到时候调试数据库出问题都不知道怎么处理,走一步看一步了,非常感谢。
参考就是Codelab里面的例子和官方文档。
更多关于HarmonyOS 鸿蒙Next中关系数据库使用的实战教程也可以访问 https://www.itying.com/category-93-b0.html
鸿蒙Next中关系数据库使用
基于关系型数据库(RDB)组件。该组件提供SQLite本地数据库管理能力,支持标准SQL语法进行数据操作。开发时需导入@ohos.data.relationalStore模块,通过getRdbStore()获取数据库实例。主要操作包括创建表、增删改查数据、事务处理等。数据存储于应用沙箱路径下,安全隔离。
你的代码结构清晰,已经覆盖了关系型数据库的基本操作。针对冗余和数据隐患的问题,可以从以下几个方面优化:
1. 使用ORM思想简化数据映射
可以封装一个通用的BaseEntity类来处理ValuesBucket的转换,避免每个表都重复编写字段映射代码。
abstract class BaseEntity<T> {
abstract toValuesBucket(): relationalStore.ValuesBucket;
static fromResultSet<T>(resultSet: relationalStore.ResultSet): T;
}
2. 统一SQL执行与错误处理
创建executeSql方法统一处理执行和日志记录:
private async executeSql(sql: string, params?: any[]): Promise<relationalStore.ResultSet> {
return this.objectiveRDB?.querySql(sql, params).then((resultSet) => {
hilog.info(0x0000, TAG, `Execute SQL success: ${sql}`);
return resultSet;
}).catch((err: BusinessError) => {
hilog.error(0x0000, TAG, `Execute SQL failed: ${sql}, error: ${err.code} - ${err.message}`);
throw err;
});
}
3. 使用RdbPredicates构建查询条件
对于条件查询,建议统一使用RdbPredicates而非拼接SQL字符串:
const predicates = new relationalStore.RdbPredicates('TODOS');
predicates.equalTo('is_done', 0)
.greaterThan('deadline', new Date().toISOString())
.orderByAsc('deadline');
4. 事务处理关键操作 对关联操作使用事务保证数据一致性:
async deleteListWithTodos(listId: number) {
await this.objectiveRDB?.transaction(async () => {
await this.deleteList(listId);
const predicates = new relationalStore.RdbPredicates('TODOS');
predicates.equalTo('list_id', listId);
await this.objectiveRDB.delete(predicates);
});
}
5. 数据库升级管理
实现onUpgrade方法处理表结构变更:
const STORE_CONFIG: relationalStore.StoreConfig = {
name: 'Objective.db',
securityLevel: relationalStore.SecurityLevel.S1,
version: 2, // 版本号
onUpgrade: (currentVersion, targetVersion) => {
// 执行表结构变更
}
};
6. 类型安全增强 为查询结果添加更严格的类型校验:
interface TodoRecord extends TodoTmp {
id: number;
created_at: string;
}
const todo = await this.queryOne<TodoRecord>(predicates);
7. 连接池与生命周期管理
在EntryAbility的onCreate中初始化,在onDestroy中释放资源:
// EntryAbility.ets
onCreate() {
RDBStoreUtil.createObjectiveRDB(this.context);
}
onDestroy() {
RDBStoreUtil.close();
}
这些优化方向能提升代码的可维护性和数据安全性,同时保持HarmonyOS关系型数据库的最佳实践。

