前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >鸿蒙开发实战案例:TaskPool线程中操作关系型数据库实现案例思路

鸿蒙开发实战案例:TaskPool线程中操作关系型数据库实现案例思路

原创
作者头像
小帅聊鸿蒙
发布2025-02-21 13:50:16
发布2025-02-21 13:50:16
1060
举报
文章被收录于专栏:鸿蒙开发笔记鸿蒙开发笔记

介绍

本示例通过通讯录场景实例进行讲解,介绍了在 TaskPool 线程中操作关系型数据库的方法,涵盖了单条插入(新增联系人)、批量插入(通讯录同步)、删除(删除联系人)、修改(更新联系人信息)和查询等基本操作。

效果图预览

使用说明

  1. 首次进入页面,出现“点击同步通讯录数据”按钮。点击按钮后,将本地 JSON 数据分批插入数据库中。
  2. 同步完成后,页面显示通讯录列表。点击列表项进入联系人的详情页面,点击加号按钮进入新增联系人页面。
  3. 在详情页面,可以对联系人信息进行修改和删除操作。

实现思路

  1. 首先,构建一个关系型数据库并封装数据库操作方法涉及几个关键步骤。
  2. 通过getRdbStore方法初始化一个关系型数据库,用户可以根据STORE_CONFIG配置RdbStore的参数,使用Promise异步回调。
代码语言:ts
复制
  // 初始化数据库 
  public async initRdbStore(context: common.Context): Promise<void> {
    this.rdbStore = await rdb.getRdbStore(context, STORE_CONFIG);
    await this.createTable();
  }使用executeSql接口初始化数据库表结构和相关数据。// 创建数据库表
  private async createTable(): Promise<void> { 
  await this.rdbStore.executeSql(SQL_CREATE_TABLE);
}
  • 封装数据库操作方法分别为数据插入、数据删除、数据查询和数据查询。
代码语言:ts
复制
  // 单条数据插入数据库
  public async insertData(context: common.Context, Contact: Contact): Promise<void> {
    let value1 = Contact.name;
    let value2 = Contact.phone;
    let value3 = Contact.email;
    let value4 = Contact.address;
    let value5 = Contact.avatar;
    let value6 = Contact.category;

    const valueBucket: ValuesBucket = {
      'name': value1,
      'phone': value2,
      'email': value3,
      'address': value4,
      'avatar': value5,
      'category': value6
    }
    if (this.rdbStore != undefined) {
      let ret = await this.rdbStore.insert(TABLE_NAME, valueBucket, rdb.ConflictResolution.ON_CONFLICT_REPLACE);
    }
  }

  // 批量插入数据库
  public async batchInsertData(context: common.Context, array: Array<Contact>): Promise<void> {
    let valueBuckets: Array<ValuesBucket> = [];
    for (let index = 0; index < array.length; index++) {
      let contactItem = array[index] as Contact;
      let value1 = contactItem.name;
      let value2 = contactItem.phone;
      let value3 = contactItem.email;
      let value4 = contactItem.address;
      let value5 = contactItem.avatar;
      let value6 = contactItem.category;

      const valueBucket: ValuesBucket = {
        'name': value1,
        'phone': value2,
        'email': value3,
        'address': value4,
        'avatar': value5,
        'category': value6
      }
      valueBuckets.push(valueBucket);
    }
    if (this.rdbStore != undefined) {
      let ret = await this.rdbStore.batchInsert(TABLE_NAME, valueBuckets);
    }
  }

  // 删除操作
  public async deleteData(context: common.Context, Contact: Contact): Promise<void> { 
    this.rdbStore = await rdb.getRdbStore(context, STORE_CONFIG);

    predicates.or().equalTo('id', Contact.id);
    this.rdbStore.delete(predicates, (err: BusinessError, row: number) => {
      if (err) {
        logger.info(TAG, "delete failed, err: " + err);
        return;
      }
      logger.info(TAG, `delete contact success:${row}`);
      promptAction.showToast({
        message: $r('app.string.operate_rdb_in_taskpool_delete_prompt_text', Contact.name),
        duration: CommonConstants.PROMPT_DURATION_TIME
      });
    });

  }

  // 更新数据库
  public async updateData(context: common.Context, Contact: Contact): Promise<void> {
    logger.info(TAG, 'update begin');
    if (!context) {
      logger.info(TAG, 'context is null or undefined');
    }

    const predicates = new rdb.RdbPredicates(TABLE_NAME);
    if (predicates === null || predicates === undefined) {
      logger.info(TAG, 'predicates is null or undefined');
    }

    if (!this.rdbStore) {
      logger.info(TAG, 'update rdbStore is null');
      await this.initRdbStore(context);
    }
    let value1 = Contact.name;
    let value2 = Contact.phone;
    let value3 = Contact.email;
    let value4 = Contact.address;
    let value5 = Contact.avatar;
    let value6 = Contact.category;

    const valueBucket: ValuesBucket = {
      'name': value1,
      'phone': value2,
      'email': value3,
      'address': value4,
      'avatar': value5,
      'category': value6
    }

    predicates.equalTo("id", Contact.id);

    if (this.rdbStore != undefined) {
      this.rdbStore.update(valueBucket, predicates, rdb.ConflictResolution.ON_CONFLICT_REPLACE,
        (err: BusinessError, row: number) => {
          if (err) {
            logger.info(TAG, "updated failed, err: " + err)
            return
          }
          logger.info(TAG, `update done:${row}`);
          promptAction.showToast({
            message: $r('app.string.operate_rdb_in_taskpool_update_prompt_text', Contact.name),
            duration: CommonConstants.PROMPT_DURATION_TIME
          });
        })
    }
  }
  
  // 查询数据库
  public async query(context: common.Context): Promise<Array<Contact>> {
    if (!context) {
      logger.info(TAG, 'context is null or undefined');
      return [];
    }

    let predicates = new rdb.RdbPredicates(TABLE_NAME);
    predicates.orderByAsc("category")
    if (predicates === null || predicates === undefined) {
      logger.info(TAG, 'predicates is null or undefined');
      return [];
    }

    try {
      this.rdbStore = await rdb.getRdbStore(context, STORE_CONFIG);
      const resultSet: rdb.ResultSet =
        await this.rdbStore.query(predicates);
      logger.info(TAG, 'result is ' + JSON.stringify(resultSet.rowCount));
      // 处理查询到的结果数组
      return this.getListFromResultSet(resultSet);
    } catch (err) {
      logger.error(TAG, 'query result error:' + JSON.stringify(err));
      return [];
    }
  }
DD一下:欢迎大家关注公众号<程序猿百晓生>,可以了解到一下知识点。
代码语言:erlang
复制
1.OpenHarmony开发基础
2.OpenHarmony北向开发环境搭建
3.鸿蒙南向开发环境的搭建
4.鸿蒙生态应用开发白皮书V2.0 & V3.0
5.鸿蒙开发面试真题(含参考答案) 
6.TypeScript入门学习手册
7.OpenHarmony 经典面试题(含参考答案)
8.OpenHarmony设备开发入门【最新版】
9.沉浸式剖析OpenHarmony源代码
10.系统定制指南
11.【OpenHarmony】Uboot 驱动加载流程
12.OpenHarmony构建系统--GN与子系统、部件、模块详解
13.ohos开机init启动流程
14.鸿蒙版性能优化指南
.......
  1. 创建任务池(taskpool)为数据库操作提供一个多线程的运行环境,将创建好的任务(新增、删除、修改、查询操作)放入taskpool内部任务队列,在子线程中实现数据库增删改查的任务,以此防止阻塞主线程。执行完成后,将结果回调至主线程,从而在主线程中更新数据源和用户界面。这样做不仅提升了应用的响应速度,还确保了用户交互的流畅性。以下代码以查询为例:(注:任务不会立即执行,而是等待分发到工作线程执行。)
代码语言:ts
复制
  // queryItem函数调用 需使用装饰器@Concurrent
  @Concurrent
  async function queryItem(context: common.Context): Promise<Array<Contact>> {
    return await DatabaseConnection.getInstance().query(context);
  }
 
  export async function taskPoolExecuteQuery(context: common.Context): Promise<Array<Contact>> {
    try {
      let task: taskPool.Task = new taskPool.Task(queryItem, context); // queryItem函数调用 需使用装饰器@Concurrent
      let result: Array<Contact> = await taskPool.execute(task) as Array<Contact>;
      return result;
    } catch (err) {
      logger.error(TAG, 'query error:' + JSON.stringify(err));
      return [];
    }
  }
  1. 在taskpool线程中操作关系型数据库方法的调用,将结果回调至主线程,在回调中来操作数据源。
代码语言:ts
复制
    // 单条数据插入操作
    taskPoolExecuteInsert(context, this.result).then(() => {
        DynamicsRouter.popAppRouter();
        // 数据库插入成功后 操作列表数据源回调
        this.addCallback(this.result);
    });

    // 数据删除操作
    taskPoolExecuteDelete(context, this.contact).then(() => {
        if (this.sourceData) {
            // 数据库删除成功后 操作列表数据源
            DynamicsRouter.popAppRouter();
            this.deleteCallback(this.sourceData);
        }

    // 更新数据操作
    taskPoolExecuteUpdate(context, this.result).then(() => {
        DynamicsRouter.popAppRouter();
        // 数据库更新成功后 操作列表数据源回调
        this.editCallback(this.result);
    });

    // 数据查询操作
    queryRDB() {
        taskPoolExecuteQuery(context).then((contact: Array<Contact>) => {
            this.dataArray = contact.reduce((accumulator, item) => {
                // 如果类别不存在,则创建一个新的数组
                if (!accumulator[item.category]) {
                    accumulator[item.category] = [];
                }
                // 将当前项添加到相应类别的数组中
                accumulator[item.category].push(item);
                return accumulator;
            }, {} as Record<string, Contact[]>);

            // 清空类别数组
            this.categoryArray = [];

            // 使用 Object.entries() 遍历键值对
            Object.entries(this.dataArray).forEach(data => {
                let categoryContact: CategoryContact = { category: data[0], itemsContact: data[1] }
                this.categoryArray.push(data[0]);
                this.sourceArray.pushData(categoryContact);
            });
        });
    }

高性能知识点

本示例使用了LazyForEach 进行数据懒加载,LazyForEach懒加载可以通过设置cachedCount属性来指定缓存数量,同时搭配组件复用能力以达到性能最优效果。

工程结构&模块类型

代码语言:shell
复制
operaterdbintaskpool                             // har类型
|---constant
|   |---CommonConstant.ets                       // 常量
|   |---RdbConstant.ets                          // Rdb常量
|---model
|   |---Contact.ets                              // Contact数据结构
|   |---DataSource.ets                           // 解析JSON数据 
|   |---DataSource.ets                           // 列表数据模型
|---view
|   |---AddressBookDetail.ets                    // 通讯录详情页
|   |---AddressBookEdit.ets                      // 通讯录编辑和新增页
|   |---AddressBookList.ets                      // 通讯录列表页
|   |---DatabaseConnection.ets                   // 数据库相关操作
|   |---OpetateRDBTaskPool.ets                   // 主页面
|   |---TaskPool.ets                             // TaskPool线程

写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力;
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识;
  • 想要获取更多完整鸿蒙最新学习知识点,可关注B站:码牛课堂;

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 效果图预览
  • 实现思路
    • DD一下:欢迎大家关注公众号<程序猿百晓生>,可以了解到一下知识点。
  • 高性能知识点
  • 工程结构&模块类型
  • 写在最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档