HarmonyOS NEXT 使用 relationalStore 实现数据库操作

大家好,我是V哥。在 HarmonyOS NEXT 开发中,如何操作数据库,V 哥在测试中总结了以下学习代码,分享给你,如何想要系统学习鸿蒙开发,可以了解一下 V 哥最近刚刚上架出版的 《HarmonyOS 鸿蒙开发之路 卷2 从入门到应用篇》,V 哥在这本书里系统的介绍纯血鸿蒙的细枝末节,可以让零基础的朋友快速上手鸿蒙应用开发。

在鸿蒙开发中,系统 API 提供了基于SQLite组件的一套完整的对本地数据库进行管理的机制,对外提供了一系列的增、删、改、查等接口,也可以直接运行用户输入的SQL语句来满足复杂的场景需要。支持通过ResultSet.getSendableRow方法获取Sendable数据,进行跨线程传递。

这里要注意一下,为保证插入并读取数据成功,建议一条数据不超过2MB。如果数据超过2MB,插入操作将成功,读取操作将失败。

大数据量场景下查询数据可能会导致耗时长甚至应用卡死,如有相关操作可参考文档批量数据写数据库场景,且有建议如下:

  • 单次查询数据量不超过5000条。
  • 在TaskPool中查询。
  • 拼接SQL语句尽量简洁。
  • 合理地分批次查询。

该模块提供以下关系型数据库相关的常用功能:

  • RdbPredicates:数据库中用来代表数据实体的性质、特征或者数据实体之间关系的词项,主要用来定义数据库的操作条件。
  • RdbStore:提供管理关系数据库(RDB)方法的接口。
  • ResultSet:提供用户调用关系型数据库查询接口之后返回的结果集合。
  • Transaction:提供管理事务对象的接口。

案例代码

接下来,V 哥通一个完整案例来介绍如何使用。

typescript 复制代码
import relationalStore from '@ohos.data.relationalStore';
import promptAction from '@ohos.promptAction';

@Entry
@Component
struct RdbStoreExample {
  @State userList: Array<{ id: number; name: string; age: number }> = [];
  @State nameInput: string = '';
  @State ageInput: string = '';
  private rdbStore: relationalStore.RdbStore | null = null;
  private rdbConfig: relationalStore.RdbStoreConfig = {
    name: 'UserData.db',
    securityLevel: relationalStore.SecurityLevel.S1
  };
  private CREATE_TABLE_USER = 
    'CREATE TABLE IF NOT EXISTS User (' +
    'id INTEGER PRIMARY KEY AUTOINCREMENT, ' +
    'name TEXT NOT NULL, ' +
    'age INTEGER NOT NULL)';

  aboutToAppear() {
    this.openRdbStore();
  }

  aboutToDisappear() {
    this.closeRdbStore();
  }

  // 打开数据库
  async openRdbStore() {
    try {
      this.rdbStore = await relationalStore.getRdbStore(this.rdbConfig, 1, 
        (version: number, rdbStore: relationalStore.RdbStore) => {
          if (version === 1) {
            rdbStore.executeSql(this.CREATE_TABLE_USER, []);
          }
        });
      await this.queryUsers();
    } catch (error) {
      console.error(`Failed to open RDB store: ${error}`);
      promptAction.showToast({ message: '数据库打开失败' });
    }
  }

  // 关闭数据库
  async closeRdbStore() {
    if (this.rdbStore) {
      try {
        await this.rdbStore.close();
        this.rdbStore = null;
      } catch (error) {
        console.error(`Failed to close RDB store: ${error}`);
      }
    }
  }

  // 插入数据
  async insertUser() {
    if (!this.nameInput || !this.ageInput) {
      promptAction.showToast({ message: '请输入姓名和年龄' });
      return;
    }
    
    try {
      const valuesBucket = {
        name: this.nameInput,
        age: parseInt(this.ageInput)
      };
      
      const id = await this.rdbStore?.insert('User', valuesBucket);
      if (id && id > 0) {
        promptAction.showToast({ message: '插入成功' });
        await this.queryUsers();
        this.nameInput = '';
        this.ageInput = '';
      }
    } catch (error) {
      console.error(`Failed to insert data: ${error}`);
      promptAction.showToast({ message: '插入失败' });
    }
  }

  // 查询数据
  async queryUsers() {
    try {
      const resultSet = await this.rdbStore?.querySql(
        'SELECT * FROM User', []);
      
      if (resultSet) {
        const users = [];
        resultSet.goToFirstRow();
        
        while (!resultSet.isAtEnd()) {
          users.push({
            id: resultSet.getLong(resultSet.getColumnIndex('id')),
            name: resultSet.getString(resultSet.getColumnIndex('name')),
            age: resultSet.getInt(resultSet.getColumnIndex('age'))
          });
          resultSet.goToNextRow();
        }
        
        this.userList = users;
        resultSet.close();
      }
    } catch (error) {
      console.error(`Failed to query data: ${error}`);
      promptAction.showToast({ message: '查询失败' });
    }
  }

  // 更新数据
  async updateUser(id: number, name: string, age: number) {
    try {
      const valuesBucket = {
        name: name,
        age: age
      };
      
      const conditions = new relationalStore.RdbStorePredicates('User');
      conditions.equalTo('id', id.toString());
      
      const rowsAffected = await this.rdbStore?.update(
        valuesBucket, conditions);
      
      if (rowsAffected && rowsAffected > 0) {
        promptAction.showToast({ message: '更新成功' });
        await this.queryUsers();
      }
    } catch (error) {
      console.error(`Failed to update data: ${error}`);
      promptAction.showToast({ message: '更新失败' });
    }
  }

  // 删除数据
  async deleteUser(id: number) {
    try {
      const conditions = new relationalStore.RdbStorePredicates('User');
      conditions.equalTo('id', id.toString());
      
      const rowsAffected = await this.rdbStore?.delete(conditions);
      
      if (rowsAffected && rowsAffected > 0) {
        promptAction.showToast({ message: '删除成功' });
        await this.queryUsers();
      }
    } catch (error) {
      console.error(`Failed to delete data: ${error}`);
      promptAction.showToast({ message: '删除失败' });
    }
  }

  build() {
    Column() {
      // 输入表单
      Column() {
        Input({
          placeholder: '请输入姓名',
          type: InputType.Text
        })
        .width('100%')
        .margin({ top: 10, bottom: 10 })
        .onChange((value: string) => {
          this.nameInput = value;
        })
        
        Input({
          placeholder: '请输入年龄',
          type: InputType.Number
        })
        .width('100%')
        .margin({ top: 10, bottom: 10 })
        .onChange((value: string) => {
          this.ageInput = value;
        })
        
        Button('添加用户')
        .width('100%')
        .onClick(() => {
          this.insertUser();
        })
      }
      .width('90%')
      .margin({ top: 20, bottom: 20 })
      
      // 用户列表
      List() {
        ForEach(this.userList, (user) => {
          ListItem() {
            Row() {
              Column() {
                Text(`姓名: ${user.name}`)
                Text(`年龄: ${user.age}`)
              }
              .width('70%')
              
              Column() {
                Button('修改')
                .onClick(() => {
                  const newName = promptAction.showPromptDialog({
                    message: '请输入新姓名',
                    defaultValue: user.name
                  });
                  const newAge = promptAction.showPromptDialog({
                    message: '请输入新年龄',
                    defaultValue: user.age.toString()
                  });
                  if (newName && newAge) {
                    this.updateUser(user.id, newName, parseInt(newAge));
                  }
                })
                
                Button('删除')
                .onClick(() => {
                  this.deleteUser(user.id);
                })
              }
              .width('30%')
            }
            .width('100%')
          }
        })
      }
      .width('90%')
      .margin({ top: 10, bottom: 10 })
    }
    .width('100%')
    .height('100%')
    .padding(15)
  }
}

下面来解释下这个示例:

  1. 首先要创建数据库配置并打开数据库,在openRdbStore方法里完成这些操作,创建了一个名为UserData.db的数据库,还定义了建表语句。

  2. 插入数据时,使用insert方法,把姓名和年龄封装成valuesBucket对象传进去,插入成功后会更新用户列表。

  3. 查询数据是通过querySql方法执行SQL语句,然后遍历结果集把数据存到userList里。

  4. 更新数据用update方法,要先创建RdbStorePredicates对象设置更新条件,根据ID来更新对应的记录。

  5. 删除数据也是先创建条件对象,然后调用delete方法,根据ID删除记录。

  6. 在界面上,提供了输入框让用户输入姓名和年龄,还有添加按钮,下面展示用户列表,每条记录都有修改和删除按钮。

操作技巧总结如下

  1. 打开和关闭数据库操作要在页面生命周期的合适时机进行,比如在aboutToAppear时打开,aboutToDisappear时关闭。
  2. 执行数据库操作时一定要进行异常处理,避免程序崩溃。
  3. 使用预编译语句可以提高性能,特别是在批量操作的时候。
  4. 操作完成后要及时关闭ResultSet,释放资源。
  5. 合理设计表结构,设置合适的主键和索引能提升查询效率。
  6. 更新和删除操作记得设置好条件,防止误操作。
  7. 对于复杂查询,可以使用原生SQL语句,但要注意SQL注入问题。

好了,以上内容供你参考,学习鸿蒙开发,抢占市场风口,国产化之路,V 哥与你搀扶前行。

相关推荐
坚果派·白晓明7 分钟前
三方库ada
harmonyos·鸿蒙·openharmony
坚果派·白晓明15 分钟前
三方库 nanomsg
华为·harmonyos
不想看见40443 分钟前
Qt 项目中实现良好封装(模块化设计)的详细流程指南
数据库·系统架构
mygljx1 小时前
MySQL 数据库连接池爆满问题排查与解决
android·数据库·mysql
Jeremy爱编码1 小时前
软考数据库
数据库
Bdygsl2 小时前
MySQL(1)—— 基本概念和操作
数据库·mysql
zongzizz2 小时前
Oracle 11g 两节点rac在机房断电重启后PL/SQL和客户端连接数据库报错ORA-12541
数据库·oracle
qq_417695052 小时前
实战:用OpenCV和Python进行人脸识别
jvm·数据库·python
身如柳絮随风扬2 小时前
什么是左匹配规则?
数据库·sql·mysql
xinhuanjieyi2 小时前
ruoyimate导入sql\antflow\bpm_init_db.sql报错
android·数据库·sql