四、【鸿蒙 NEXT】关系型数据库创建与升级

145 阅读4分钟

前言:

在app开发过程中,关系型数据库基本都会用到,纯血鸿蒙的关系型数据库底层也是sqllite,只不过纯血鸿蒙用的是ArtTS语法写的。本章就讲解下如何用ArtTS语法来进行关系型数据库的创建与升级。

一、基本使用方法

主要分3个步骤

(1)定义数据库的配置

(2)获取数据库的实例对象rdbStore

(3)根据数据库版本号来执行不同的sql

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

export class DBTest {
  /**
   * 1、定义数据库配置文件
   * 2、获取数据库实例对象rdbStore
   * 3、根据版本号执行不同sql
   *
   * @param context
   */
  async createOrUpdate(context: common.UIAbilityContext) {
    // 1、定义数据库配置文件
    const config: relationalStore.StoreConfig = {
      name: "rdbTest.db",
      securityLevel: relationalStore.SecurityLevel.S2, // 数据库安全级别
      encrypt: false // 数据库是否加密
    }
    // 2、获取数据库实例对象rdbStore
    let rdbStore = await relationalStore.getRdbStore(context, config);
    // 3、根据版本号执行不同sql
    if (rdbStore.version === 0) {
      rdbStore.executeSql('CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER)')
      rdbStore.version = 1
    }
    if (rdbStore.version === 1) {
      rdbStore.executeSql('ALTER TABLE EMPLOYEE ADD COLUMN sex Text');
      rdbStore.version = 2
    }
    if (rdbStore.version === 2) {
      rdbStore.executeSql('ALTER TABLE EMPLOYEE ADD COLUMN ADDRESS TEXT');
      rdbStore.version = 3
    }
  }
}

securityLevel配置:

鸿蒙系统对于应用数据的存放分为了el1~el5目录,安全级别逐次提高,如果不涉及高敏感数据可以存在el1和el2目录,也就是securityLevel.S1和securityLevel.S2的配置。如果涉及高敏感数据,可以放在el3目录或者el4目录,这两个目录的区别就是在锁屏场景下,el3可以创建文件,但不可以读取文件,锁屏场景会读取失败。而el4目录是既不可以创建也不能读取。el1和el2目录锁屏场景下应用可以正常读取。

encrypt配置:

该配置很直观就是是否给数据库加密,如果是true,相当于整个数据库文件是加密状态。如果数据库中存在敏感个人数据,可以设置为true。但是不影响使用接口获取数据。无论加密还是不加密,接口访问数据的方式都一样,都是通过rdbStore对象访问。只不过数据库文件无法用一些sqllite工具直接查看。如果想用sqllite工具查看数据库文件,需要将endrypt设置为false才行。

二、更优雅的实现数据的升级

考虑到随着app版本迭代,数据库升级可能会越来越多,版本的if判断也会越来越多,不利于代码的维护和扩展,可以将升级操作抽取为多态类。

完整的实现如下:

定义一个IRdbUpgrade接口,每次数据库需要升级时,新增一个实现类,无需修改主流程代码。

主流程代码:

import { common } from '@kit.AbilityKit';
import { relationalStore } from '@kit.ArkData';
import { IRdbUpgrade } from './IRdbUpgrade';
import { V2RdbUpgrade } from './V2RdbUpgrade';
import { V3RdbUpgrade } from './V3RdbUpgrade';

export class DBTest2 {
  // 最新的目标版本
  private targetVersion = 3;

  async createOrUpdate(context: common.UIAbilityContext) {
    // 1、定义数据库配置文件
    const config: relationalStore.StoreConfig = {
      name: "rdbTest.db",
      securityLevel: relationalStore.SecurityLevel.S2, // 数据库安全级别
      encrypt: false // 数据库是否加密
    }
    // 2、获取数据库实例对象rdbStore
    let rdbStore = await relationalStore.getRdbStore(context, config);
    // 3、根据版本号执行不同sql
    switch (rdbStore.version) {
      case 0:
        // app新安装场景,创建表
        this.doCreate(rdbStore);
        break;
      default:
        // app升级场景,升级数据库
        this.doUpgrade(rdbStore);
    }
  }

  async doCreate(rdbStore: relationalStore.RdbStore) {
    try {
      rdbStore.beginTransaction(); // 开启事务
      await rdbStore.executeSql('xxxxx');
      await rdbStore.executeSql('xxxxx');
      await rdbStore.executeSql('xxxxx');
      // 修改数据库版本
      rdbStore.version = this.targetVersion;
      rdbStore.commit();
    } catch (e) {
      rdbStore.rollBack();
    }
  }

  upgradeOper: IRdbUpgrade[] = [new V2RdbUpgrade(), new V3RdbUpgrade()];

  async doUpgrade(rdbStore: relationalStore.RdbStore) {
    // 过滤出大于当前版本的升级类,并把所有升级类按照版本从小到大排序,一次执行升级操作
    let sortUpgradeOper = this.upgradeOper
      .sort((pre, post) => pre.getVersion() - post.getVersion())
      .filter((upgrade) => upgrade.getVersion() > rdbStore.version);
    try {
      rdbStore.beginTransaction();
      for (let i = 0; i< sortUpgradeOper.length; i++) {
        await sortUpgradeOper[i].doUpgrade(rdbStore);
      }
      rdbStore.version = this.targetVersion;
      rdbStore.commit();
    } catch (e) {
      rdbStore.rollBack();
    }
  }


}

IRdbUpgrade接口:

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

export interface IRdbUpgrade {
  // 做数据库升级操作
  doUpgrade(rdbStore: relationalStore.RdbStore): Promise<void>;

  // 返回当前操作的数据库版本
  getVersion(): number;
}

版本2的实现类:

import { IRdbUpgrade } from './IRdbUpgrade';
import relationalStore from '@ohos.data.relationalStore';

/**
 * 实现数据库版本1升级到版本2的数据库操作
 */
export class V2RdbUpgrade implements IRdbUpgrade {
  async doUpgrade(rdbStore: relationalStore.RdbStore): Promise<void> {
    await rdbStore.executeSql('xxxx');
    await rdbStore.executeSql('xxxx');
    await rdbStore.executeSql('xxxx');
  }

  getVersion(): number {
    return 2;
  }

}

版本3的实现类:

import { IRdbUpgrade } from './IRdbUpgrade';
import relationalStore from '@ohos.data.relationalStore';

/**
 * 实现数据库版本2升级到版本3的数据库操作
 */
export class V3RdbUpgrade implements IRdbUpgrade {
  async doUpgrade(rdbStore: relationalStore.RdbStore): Promise<void> {
    await rdbStore.executeSql('xxxx');
    await rdbStore.executeSql('xxxx');
    await rdbStore.executeSql('xxxx');
  }

  getVersion(): number {
    return 3;
  }

}

如果后续有新增升级操作,步骤如下:

(1)新增一个实现类继承IRdbUpgrade接口

(2)并将targetVersion加1

(3)在数组upgradeOper: IRdbUpgrade[] = [new V2RdbUpgrade(), new V3RdbUpgrade()];中将新加的实现类加入数组中。