HarmonyOS 鸿蒙Next中如何使用RelationalStore实现数据库的增删改查(CRUD)操作?

HarmonyOS 鸿蒙Next中如何使用RelationalStore实现数据库的增删改查(CRUD)操作? 遇到的问题:

  • 不清楚如何正确初始化数据库
  • 不知道如何设计Dao层
  • 查询结果集如何转换为对象
  • 如何处理异步操作
3 回复

解决方案

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 鸿蒙Next中如何使用RelationalStore实现数据库的增删改查(CRUD)操作?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中使用RelationalStore进行CRUD操作

在HarmonyOS Next中,使用RelationalStore进行CRUD操作的基本流程如下:

获取数据库实例

首先通过 getRdbStore 方法获取数据库实例。

创建表

使用 executeSql 方法执行CREATE语句来创建表。

插入数据

调用 insert 方法插入数据。

查询数据

使用 queryquerySql 方法查询数据。

更新数据

调用 update 方法更新数据。

删除数据

使用 delete 方法删除数据。

注意事项

  • 所有操作需在获取的RdbStore实例上完成。
  • 注意处理异步回调。

在HarmonyOS Next中,使用RelationalStore进行CRUD操作的核心流程如下:

1. 数据库初始化

首先在module.json5中声明权限:

"requestPermissions": [
  {
    "name": "ohos.permission.DISTRIBUTED_DATASYNC"
  }
]

然后初始化RdbStore:

import { relationalStore } from '@kit.ArkData';

const STORE_CONFIG: relationalStore.StoreConfig = {
  name: 'MyApplication.db',
  securityLevel: relationalStore.SecurityLevel.S1
};
let rdbStore: relationalStore.RdbStore | undefined = undefined;

// 初始化数据库
async function initRdbStore(context: Context) {
  try {
    rdbStore = await relationalStore.getRdbStore(context, STORE_CONFIG);
    // 创建表
    const sql = `CREATE TABLE IF NOT EXISTS user (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL,
      age INTEGER
    )`;
    await rdbStore.executeSql(sql);
  } catch (err) {
    console.error(`Failed to init RdbStore. Code:${err.code}, message:${err.message}`);
  }
}

2. Dao层设计

建议采用面向对象方式封装:

export class UserDao {
  private rdbStore: relationalStore.RdbStore;

  constructor(rdbStore: relationalStore.RdbStore) {
    this.rdbStore = rdbStore;
  }

  // 插入数据
  async insert(user: User): Promise<number> {
    const valueBucket: relationalStore.ValuesBucket = {
      'name': user.name,
      'age': user.age
    };
    try {
      return await this.rdbStore.insert('user', valueBucket);
    } catch (err) {
      console.error(`Failed to insert data. Code:${err.code}, message:${err.message}`);
      return -1;
    }
  }

  // 查询数据
  async queryAll(): Promise<User[]> {
    const predicates = new relationalStore.RdbPredicates('user');
    try {
      const resultSet = await this.rdbStore.query(predicates, ['id', 'name', 'age']);
      return this.convertResultSetToUsers(resultSet);
    } catch (err) {
      console.error(`Failed to query data. Code:${err.code}, message:${err.message}`);
      return [];
    }
  }

  // 更新数据
  async update(user: User): Promise<number> {
    const predicates = new relationalStore.RdbPredicates('user');
    predicates.equalTo('id', user.id);
    
    const valueBucket: relationalStore.ValuesBucket = {
      'name': user.name,
      'age': user.age
    };
    
    try {
      return await this.rdbStore.update(valueBucket, predicates);
    } catch (err) {
      console.error(`Failed to update data. Code:${err.code}, message:${err.message}`);
      return 0;
    }
  }

  // 删除数据
  async delete(id: number): Promise<number> {
    const predicates = new relationalStore.RdbPredicates('user');
    predicates.equalTo('id', id);
    
    try {
      return await this.rdbStore.delete(predicates);
    } catch (err) {
      console.error(`Failed to delete data. Code:${err.code}, message:${err.message}`);
      return 0;
    }
  }

  // 结果集转换
  private convertResultSetToUsers(resultSet: relationalStore.ResultSet): User[] {
    const users: User[] = [];
    while (resultSet.goToNextRow()) {
      const user = new User();
      user.id = resultSet.getLong(resultSet.getColumnIndex('id'));
      user.name = resultSet.getString(resultSet.getColumnIndex('name'));
      user.age = resultSet.getLong(resultSet.getColumnIndex('age'));
      users.push(user);
    }
    resultSet.close();
    return users;
  }
}

3. 实体类定义

export class User {
  id: number = 0;
  name: string = '';
  age: number = 0;
}

4. 异步处理

所有RelationalStore操作都是异步的,需要使用async/await或Promise:

// 使用示例
async function demo() {
  await initRdbStore(getContext(this));
  const userDao = new UserDao(rdbStore!);
  
  // 插入
  const newUser = new User();
  newUser.name = '张三';
  newUser.age = 25;
  const insertId = await userDao.insert(newUser);
  
  // 查询
  const users = await userDao.queryAll();
  
  // 更新
  if (users.length > 0) {
    users[0].name = '李四';
    await userDao.update(users[0]);
  }
  
  // 删除
  if (insertId > 0) {
    await userDao.delete(insertId);
  }
}

关键点:

  • 使用RdbPredicates构建查询条件
  • 通过ValuesBucket进行数据绑定
  • 结果集操作后必须调用close()释放资源
  • 所有数据库操作都需要异常处理
  • 确保在UI线程外执行耗时操作

这种设计模式清晰分离了数据访问逻辑,便于维护和扩展。

回到顶部