• 作者:老汪软件技巧
  • 发表时间:2024-09-01 04:01
  • 浏览量:

前言:我们的App加载数据很多都是采用本地化数据,数据都是存在数据库中的,本地有个小型数据库,所有的主数据都存在本地,用来支撑业务数据的展示,业务逻辑处理。之前在安卓系统和ios系统上都是轻车熟路的,网上的方法也比较多,但是到了鸿蒙系统,只有官方资料可查,或者开源的demo可参考,本人基于同事以及自己开发中发现的问题,鸿蒙系统的数据库操作整理一份博客,一起记录问题,并解决问题。

相关类介绍:

DatabaseHelp类,主要是创建数据库,创建表

DatabaseSqlUtil类,主要是创建表的语句

ParseServerDataManager类,主要是插入数据,以及数据解析,数据整理,数据插入、删除操作

DatabaseManager类,数据库操作,增删改查

class:DatabaseSqlUtil类

export class DatabaseSqlUtil {
  // 数据库配置
  public static STORE_CONFIG :relationalStore.StoreConfig= {
    name: 'test.db', // 数据库文件名
    securityLevel: relationalStore.SecurityLevel.S1, // 数据库安全级别
    encrypt: false, // 可选参数,指定数据库是否加密,默认不加密
    customDir: 'winchannel' // 可选参数,数据库自定义路径。数据库将在如下的目录结构中被创建:context.databaseDir + '/rdb/' + customDir,其中context.databaseDir是应用沙箱对应的路径,'/rdb/'表示创建的是关系型数据库,customDir表示自定义的路径。当此参数不填时,默认在本应用沙箱目录下创建RdbStore实例。
  };
  //建表语句
  public static CREATE_BASE_STORE_TABLE:string = 'CREATE TABLE IF NOT EXISTS base_store (_id INTEGER PRIMARY KEY AUTOINCREMENT,id TEXT, name TEXT, cod TEXT, styp TEXT, addr TEXT )'
}

代码中的注释已经很清晰了。

class:DatabaseHelper

export class DatabaseHelper{
  constructor(context:Context) {
    // 获取数据库Store
    relationalStore.getRdbStore(context, DatabaseSqlUtil.STORE_CONFIG, (err, rdbStore) => {
      if (err) {
        conslog.info(`Failed to get RdbStore. Code:${err.code}, message:${err.message}`);
        return;
      }
      WinLog.info('WINLOG Succeeded in getting RdbStore.');
      this.createTable(rdbStore)
    });
  }
  /**
   * 创建表.
   */
  private createTable(rdbStore: relationalStore.RdbStore):void {
    // 判断数据库版本,如果不匹配则需进行升降级操作
    if (rdbStore == undefined){
      conslog.info('WINLOG rdbStore undefined');
      return
    }
    conslog.info('WINLOG store.version--->' + rdbStore.version);
    // 当数据库创建时,数据库默认版本为0
    if (rdbStore.version === 0) {
      rdbStore.executeSql(DatabaseSqlUtil.CREATE_BASE_STORE_TABLE);
      // 设置数据库的版本,入参为大于0的整数
      rdbStore.version = 1;
      conslog.info('WINLOG version 0 action');
    }
    // 如果数据库版本不为0且和当前数据库版本不匹配,需要进行升降级操作
    // 当数据库存在并假定版本为1时,例应用从某一版本升级到当前版本,数据库需要从1版本升级到2版本
    if (rdbStore.version === 1) {
      // version = 1:表结构:EMPLOYEE (NAME, SALARY, CODES, ADDRESS) => version = 2:表结构:EMPLOYEE (NAME, AGE, SALARY, CODES, ADDRESS)
      if (rdbStore !== undefined) {
        (rdbStore as relationalStore.RdbStore).executeSql(DatabaseSqlUtil.ALTER_BASE_ACVT_QST_COLUMN_memo);
        rdbStore.version = 2;
      }
      conslog.info('WINLOG version 1 action');
    }
  }
}

建数据库的时候有个版本控制,后续可以更新版本用来控制数据库的更新表的列,新增表操作

数据库创建库的命令__数据库创建库的语句

//表操作类:DatabaseManager

//批量数据插入,整个数组一次性插入

export class DatabaseManager{
  static batchInsertTableData(context:Context, tableName:string, bucketArray:ValuesBucket[] ){
    // 获取数据库Store
    relationalStore.getRdbStore(context, DatabaseSqlUtil.STORE_CONFIG, (err, rdbStore) => {
      if (err) {
        conslog.info(`batchInsertTableData ${tableName} Failed to get RdbStore. Code:${err.code}, message:${err.message}`);
        return;
      }
      conslog.info('batchInsertTableData Succeeded in getting RdbStore.');
      if(rdbStore != undefined) {
        (rdbStore as relationalStore.RdbStore).batchInsert(tableName, bucketArray, (err, insertNum) => {
          if (err) {
            conslog.error(`${tableName}batchInsert is failed, code is ${err.code},message is ${err.message}`);
            return;
          }
          conslog.info(`${tableName}batchInsert is successful, the number of values that were inserted = ${insertNum}`);
        })
      }
    });
  }
}

我们这里的数据比较多,用的批量插入,你的数据少的话,可以一条插入:语法:

(rdbStore as relationalStore.RdbStore).insert(tableName, bucketArray, (err, insertNum) => {
          if (err) {
            conslog.error(`${tableName}batchInsert is failed, code is ${err.code},message is ${err.message}`);
            return;
          }
          conslog.info(`${tableName}batchInsert is successful, the number of values that were inserted = ${insertNum}`);
        })

删除操作:

static deleteTableDataByTabName(context:Context, tableName:string){
    // 获取数据库Store
    relationalStore.getRdbStore(context, DatabaseSqlUtil.STORE_CONFIG, (err, rdbStore) => {
      if (err) {
        conslog.info(`${tableName} deleteTableData Failed to get RdbStore. Code:${err.code}, message:${err.message}`);
        return;
      }
      conslog.info(`deleteTableData ${tableName}  Succeeded in getting RdbStore.`);
      if(rdbStore != undefined) {
        //创建谓词,进行删除
        let rdbPredicates = new relationalStore.RdbPredicates(tableName);
        (rdbStore as relationalStore.RdbStore).delete(rdbPredicates, (err, rows) => {
          if (err) {
            conslog.info(`${tableName} Delete failed, code is ${err.code},message is ${err.message}`);
            return;
          }
          conslog.info(`${tableName} Delete rows: ${rows}`);
        })
      }
    });
  }

数据处理类:ParseServerDataManager

function parseBaseStoreData(context: Context, jsonData: string, serverNode:string){
//先删后插
  DatabaseManager.deleteTableDataByTabName(context,"base_store")
  let parseStoreList: ValuesBucket[] = []
    let storesList: BaseStore[] = JSON.parse(jsonData)[serverNode]
    if (storesList == undefined) {
      WinLog.info("stores is null")
      return
    }
    storesList.forEach((item) => {
      item.server_node = serverNode
      let storeFilter:string[] = ['id','name','empId','cod','lat','lon','addr'];
      let storeValuesBucket: ValuesBucket = JSON.parse(JSON.stringify(item,  storeFilter),replacer)
      parseStoreList.push(storeValuesBucket)
    })
    DatabaseManager.batchInsertTableData(context, "base_store", parseStoreList);
}
function replacer(key: string, value: Object): Object {
  if (key != '_id' && typeof value == 'number') {
    value = value.toString()
  }
  if (key == 'opt') {
    value = value.toString()
  }
  return value
}

这里遇到一个问题,假如你解析的数据,有object类型的,插入数据的时候,会在表里显示【object object】,JSON.parse在解析json到对象的时候,就会将object类型数据解析成object,插入数据的时候也就插入object了,这不是我想要的,我想插入的是string类型数据,

parse(text: string, reviver?: Transformer, options?: ParseOptions): Object | null

此方法就有用了,官方解释:reviverTransformer否转换函数,传入该参数,可以用来修改解析生成的原始值。默认值是undefined。传入次参数,可以指定key值不解析成object,保持原来的类型值,这个有时候开发很难注意到,希望有帮到你们。