问题描述
在 HarmonyOS 应用开发中,如何使用 RelationalStore 实现数据库的增删改查(CRUD)操作?很多开发者在使用关系型数据库时遇到以下问题:
- 不清楚如何正确初始化数据库
- 不知道如何设计 Dao 层
- 查询结果集如何转换为对象
- 如何处理异步操作
解决方案
1. 技术原理
RelationalStore 是 HarmonyOS 提供的关系型数据库解决方案,基于 SQLite 实现。核心流程:
DatabaseHelper(单例) → 初始化RdbStore → 创建表结构 → Dao层操作2. 完整实现代码
步骤 1: 创建数据库管理类
import relationalStore from '@ohos.data.relationalStore'; export class DatabaseHelper { private static instance: DatabaseHelper; private rdbStore: relationalStore.RdbStore | null = null; private readonly DB_NAME: string = 'app_database.db'; private readonly DB_VERSION: number = 1; private constructor() {} /** * 获取单例 */ static getInstance(): DatabaseHelper { if (!DatabaseHelper.instance) { DatabaseHelper.instance = new DatabaseHelper(); } return DatabaseHelper.instance; } /** * 初始化数据库 */ async init(context: Context): Promise<void> { const config: relationalStore.StoreConfig = { name: this.DB_NAME, securityLevel: relationalStore.SecurityLevel.S1 }; this.rdbStore = await relationalStore.getRdbStore(context, config); await this.createTables(); } /** * 创建表结构 */ private async createTables(): Promise<void> { const createTableSql = ` CREATE TABLE IF NOT EXISTS user ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL, nickname TEXT, email TEXT, create_time INTEGER, update_time INTEGER ) `; await this.rdbStore!.executeSql(createTableSql); } /** * 获取数据库实例 */ getStore(): relationalStore.RdbStore { if (!this.rdbStore) { throw new Error('Database not initialized'); } return this.rdbStore; } }步骤 2: 创建数据模型
export class User { id: number = 0; username: string = ''; nickname: string = ''; email: string = ''; createTime: number = 0; updateTime: number = 0; /** * 从数据库记录创建对象 */ static fromDb(record: Record<string, Object>): User { const user = new User(); user.id = record['id'] as number; user.username = record['username'] as string; user.nickname = record['nickname'] as string; user.email = record['email'] as string; user.createTime = record['create_time'] as number; user.updateTime = record['update_time'] as number; return user; } }步骤 3: 实现 Dao 层
import relationalStore from '@ohos.data.relationalStore'; import { User } from '../models/User'; import { DatabaseHelper } from './DatabaseHelper'; const TABLE_NAME = 'user'; export class UserDao { private dbHelper: DatabaseHelper; constructor() { this.dbHelper = DatabaseHelper.getInstance(); } /** * 插入用户 */ async insert(user: User): Promise<number> { const store = this.dbHelper.getStore(); const valueBucket: relationalStore.ValuesBucket = { username: user.username, nickname: user.nickname, email: user.email, create_time: Date.now(), update_time: Date.now() }; return await store.insert(TABLE_NAME, valueBucket); } /** * 更新用户 */ async update(user: User): Promise<number> { const store = this.dbHelper.getStore(); const valueBucket: relationalStore.ValuesBucket = { nickname: user.nickname, email: user.email, update_time: Date.now() }; const predicates = new relationalStore.RdbPredicates(TABLE_NAME); predicates.equalTo('id', user.id); return await store.update(valueBucket, predicates); } /** * 根据ID查询 */ async findById(id: number): Promise<User | null> { const store = this.dbHelper.getStore(); const predicates = new relationalStore.RdbPredicates(TABLE_NAME); predicates.equalTo('id', id); const resultSet = await store.query(predicates); let user: User | null = null; if (resultSet.goToFirstRow()) { const record = this.resultSetToRecord(resultSet); user = User.fromDb(record); } resultSet.close(); return user; } /** * 查询所有用户 */ async findAll(): Promise<User[]> { const store = this.dbHelper.getStore(); const predicates = new relationalStore.RdbPredicates(TABLE_NAME); const resultSet = await store.query(predicates); const users: User[] = []; while (resultSet.goToNextRow()) { const record = this.resultSetToRecord(resultSet); users.push(User.fromDb(record)); } resultSet.close(); return users; } /** * 删除用户 */ async delete(id: number): Promise<number> { const store = this.dbHelper.getStore(); const predicates = new relationalStore.RdbPredicates(TABLE_NAME); predicates.equalTo('id', id); return await store.delete(predicates); } /** * 将ResultSet转换为记录对象 */ private resultSetToRecord(resultSet: relationalStore.ResultSet): Record<string, Object> { const record: Record<string, Object> = {}; const columnNames = resultSet.columnNames; for (const name of columnNames) { const index = resultSet.getColumnIndex(name); const type = resultSet.getColumnType(index); switch (type) { case relationalStore.ColumnType.TYPE_INTEGER: record[name] = resultSet.getLong(index); break; case relationalStore.ColumnType.TYPE_STRING: record[name] = resultSet.getString(index); break; case relationalStore.ColumnType.TYPE_FLOAT: record[name] = resultSet.getDouble(index); break; default: record[name] = resultSet.getString(index); } } return record; } }步骤 4: 在 EntryAbility 中初始化
import { DatabaseHelper } from '../database/DatabaseHelper'; export default class EntryAbility extends UIAbility { async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> { // 初始化数据库 await DatabaseHelper.getInstance().init(this.context); } }步骤 5: 使用示例
import { UserDao } from '../database/UserDao'; import { User } from '../models/User'; // 创建用户 const userDao = new UserDao(); const user = new User(); user.username = 'zhangsan'; user.nickname = '张三'; user.email = 'zhangsan@example.com'; const userId = await userDao.insert(user); console.log('插入用户ID:', userId); // 查询用户 const foundUser = await userDao.findById(userId); console.log('查询到用户:', foundUser?.nickname); // 更新用户 if (foundUser) { foundUser.nickname = '张三三'; await userDao.update(foundUser); } // 查询所有用户 const allUsers = await userDao.findAll(); console.log('用户总数:', allUsers.length); // 删除用户 await userDao.delete(userId);3. 运行效果
[日志] 插入用户ID: 1 [日志] 查询到用户: 张三 [日志] 用户总数: 1 [日志] 删除成功关键要点
1. 单例模式
DatabaseHelper 使用单例模式,确保全局只有一个数据库实例,避免资源浪费。
2. 异步操作
所有数据库操作都是异步的,使用async/await确保数据一致性。
3. ResultSet 处理
- 必须调用
goToFirstRow()或goToNextRow()移动游标 - 使用完毕后必须调用
close()释放资源 - 根据列类型使用对应的 getter 方法
4. ValuesBucket
插入和更新操作使用ValuesBucket传递数据,字段名必须与表结构一致。
5. RdbPredicates
查询和删除操作使用RdbPredicates构建条件,支持链式调用:
predicates .equalTo('status', 1) .and() .greaterThan('age', 18) .orderByAsc('create_time');常见问题
Q1: 如何处理数据库初始化失败?
async init(context: Context): Promise<void> { try { const config: relationalStore.StoreConfig = { name: this.DB_NAME, securityLevel: relationalStore.SecurityLevel.S1 }; this.rdbStore = await relationalStore.getRdbStore(context, config); await this.createTables(); } catch (err) { console.error('数据库初始化失败:', JSON.stringify(err)); throw err; } }Q2: 如何实现分页查询?
async findByPage(page: number, pageSize: number): Promise<User[]> { const store = this.dbHelper.getStore(); const predicates = new relationalStore.RdbPredicates(TABLE_NAME); predicates.limitAs(pageSize).offsetAs((page - 1) * pageSize); const resultSet = await store.query(predicates); const users: User[] = []; while (resultSet.goToNextRow()) { const record = this.resultSetToRecord(resultSet); users.push(User.fromDb(record)); } resultSet.close(); return users; }Q3: 如何执行复杂 SQL 查询?
async customQuery(sql: string, args: Array<string | number>): Promise<any[]> { const store = this.dbHelper.getStore(); const resultSet = await store.querySql(sql, args); const results: any[] = []; while (resultSet.goToNextRow()) { results.push(this.resultSetToRecord(resultSet)); } resultSet.close(); return results; }总结
本文展示了 HarmonyOS 中 RelationalStore 的完整 CRUD 实现方案:
- ✅ 单例模式管理数据库实例
- ✅ 规范的 Dao 层设计
- ✅ 类型安全的数据转换
- ✅ 完善的错误处理
- ✅ 支持复杂查询
参考资料
- HarmonyOS 关系型数据库开发指南
- RelationalStore API 文档