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 哥与你搀扶前行。

相关推荐
马剑威(威哥爱编程)43 分钟前
鸿蒙 HarmonyOS NEXT 系统 Preference 首选项使用全解析
华为·harmonyos·arkts·arkui
江畔柳前堤1 小时前
PyQt学习系列07-数据库操作与ORM集成
数据库·学习·算法·机器学习·架构·pyqt
观无1 小时前
腾讯云Mysql实现远程链接
数据库·mysql
SmartSoftHelp开发辅助优化2 小时前
SmartSoftHelp 之 SQL Server 数据库安全备份与安全还原详解---深度优化版:SmartSoftHelp DeepCore XSuite
数据库·安全·oracle
朝新_2 小时前
【MySQL】第九弹——索引(下)
数据库·mysql
数据要素X3 小时前
【数据架构03】数据治理架构篇
大数据·数据库·数据仓库·架构
不思念一个荒废的名字3 小时前
【黑马JavaWeb+AI知识梳理】后端Web基础03 - MySQL概述
前端·数据库·mysql
北极光SD-WAN组网3 小时前
SD-WAN技术在远程光伏电站接入场景中的应用实践与深度解析
服务器·网络·数据库
朱友斌4 小时前
【软件安装】Windows操作系统中安装mongodb数据库和mongo-shell工具
数据库·mongodb·安装mongodb数据库·安装mongodb-shell
Le_ee4 小时前
sqli-labs第十四关——“POST报错注入
数据库·sql·mysql