4

#创作者激励# OpenHarmony关系型数据库封装前的知识要点-开源基础软件社区-51CTO.COM

 1 year ago
source link: https://ost.51cto.com/posts/22390
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

【本文正在参加2023年第一期优质创作者激励计划】

关系型数据库(Relational Database, 以下简称RDB)是一种基于关系模型来管理数据的数据库,是在SQLite基础上提供一套完整的对本地数据库进行管理的机制,为开发者提供无需编写原生SQL语句即可实现数据增、删、改、查等接口,同时开发者也可以直接运行原生SQL语句来满足复杂的场景需要。关系型数据库在应用卸载之后,才会被自动清除。

2 运作机制

RDB对外提供通用的接口,底层使用SQLite作为持久化存储引擎,支持SQLite具有的所有数据库特性。SQLite是一个进程内的库,具有自给自足、无服务、零配置、事务性特性的SQL数据库引擎。RDB包括但不限于事务、索引、视图、触发器、外键、参数化查询和预编译SQL语句。

#创作者激励# OpenHarmony关系型数据库封装前的知识要点-开源基础软件社区

3 使用场景

  • 计算器历史记录
  • App用户登录信息
  • App主题
#创作者激励# OpenHarmony关系型数据库封装前的知识要点-开源基础软件社区

5 详细步骤

RDB对开发者提供的接口大部分为异步接口,均有callbackPromise两种返回形式,接下来将会一一介绍。

5.1 导入模块

import relationalStore from '@ohos.data.relationalStore';

5.2 配置数据库相关信息

创建数据库时需要配置数据库相关信息,RDB提供管理关系型数据库配置的StoreConfig接口,其参数如表5-1所示:

表5-1 关系型数据库配置参数

名称 类型 必填 说明
name string 数据库文件名
securityLevel SecurityLevel(详见表5-2) 设置数据库安全级别
encrypt boolean 指定数据库是否加密。
true:加密。
false:非加密。

表5-2 数据库的安全级别枚举

名称 说明
S1 1 数据库安全级别为低级别,当数据泄露时会产生较低影响。如包含壁纸等系统数据的数据库。
S2 2 数据库安全级别为中级别,当数据泄露时会产生较大影响。如包含录音、视频等用户生成数据或通话记录等信息的数据库。
S3 3 数据库安全级别为高级别,当数据泄露时会产生重大影响。如包含用户运动、健康、位置等信息的数据库。
S4 4 数据库安全级别为关键级别,当数据泄露时会产生严重影响。如包含认证凭据、财务数据等信息的数据库。
const store_config = {
    name: "RdbSample.db",
    securityLevel: relationalStore.SecurityLevel.S4,
    encrypt: true
}

5.3 创建数据库

和MySQL、Oracle等数据库类似,在使用之前需要先创建数据库,RDB提供了getRdbStore()方法用于创建数据库,该方法需要传入应用上下文Context和数据库配置信息StoreConfig两个参数,该方法有callbackPromise两种返回形式,如表5-3所示。
表5-3 数据库创建方法

方法名 描述
getRdbStore(context: Context, config: StoreConfig, callback: AsyncCallback<RdbStore>): void 获得一个相关的RdbStore,操作关系型数据库。
context: 应用上下文
config: 数据库配置信息
callback: 回调函数,返回RdbStore对象
getRdbStore(context: Context, config: StoreConfig): Promise<RdbStore> 获得一个相关的RdbStore,操作关系型数据库。
context: 应用上下文
config: 数据库配置信息
Promise<RdbStore>: Promise对象,返回RdbStore对象
// callback形式
relationalStore.getRdbStore(this.context, STORE_CONFIG, (err, rdbStore) => {
  if (err) {
    Log.error(TAG, "Get RdbStore fialed, err: " + JSON.stringify(err))
    return;
  }
  // rdbStore相关操作
  Log.info(TAG, "Get RdbStore successfully.");
})

// Promise形式
relationalStore.getRdbStore(this.context, STORE_CONFIG).then((rdbStore) => {
  // rdbStore相关操作
  Log.info(TAG, "Get RdbStore successfully.");
}).catch((err) => {
  Log.error(TAG, "Get RdbStore fialed, err: " + JSON.stringify(err))
})

注:RDB不仅提供了数据库创建的方法,同时还提供了删除数据库方法,可以调用deleteRdbStore()方法进行数据库删除,使用方式和getRdbStore()方法类似。

5.4 数据表操作

创建数据库后,获取到RdbStore实例。RdbStore提供管理RDB方法的接口,在使用其增、删、改、查等接口之前,需要使用executeSql接口初始化数据表结构和相关数据。

5.4.1 创建数据表

executeSql()方法执行包含指定参数但不返回值得SQL语句,有callbackPromise两种形式,如表5-4所示。

表5-4 创建数据表方法

方法名 描述
executeSql(sql: string,bindArgs: Array<ValueType>, callback: AsyncCallback<void>): void 执行包含指定参数但不返回值得SQL语句。
sql: 指定要执行得SQL语句
bindArgs: SQL语句中参数的值
callback: 回调函数
executeSql(sql: string,bindArgs: Array<ValueType>): Promise<void> 执行包含指定参数但不返回值得SQL语句。
sql: 指定要执行得SQL语句
bindArgs: SQL语句中参数的值
Promise<void>: 无返回结果的Promise对象

注:表中的ValueType用于表示允许的数据字段类型,当前仅支持表示值类型为数字的number,表示值类型为字符的string,表示值类型为布尔值的boolean

const sql = "CREATE TABLE IF NOT EXISTS USER (ID INTEGER PRIMARY KEY AUTOINCREMENT, USERNAME TEXT NOT NULL, PASSWORD TEXT NOT NULL)"
// callback形式
rdbStore.executeSql(sql, null, (err) {
  if (err) {
    Log.error(TAG, "ExecuteSql failed, err: " + JSON.stringify(err));
    return;
  }
  Log.info(TAG, "Create table done.");
})
// Promise形式
rdbStore.executeSql(sql, null).then(() => {
  Log.info(TAG, "Create table done.");
}).catch((err) => {
  Log.error(TAG, "ExecuteSql failed, err: " + JSON.stringify(err));
})

5.4.2 新增数据

RdbStore提供了单条数据插入和批量数据插入两种为数据表新增数据的方法,如表5-5所示。

表5-5 新增数据方法

方法名 描述
insert(table: string, values: ValuesBucket, callback: AsyncCallback<number>):void 向表中插入一行数据。
table: 插入数据的目标表名称
values: 插入到表中的数据行
callback: 回调函数。插入成功,返回行ID,否则返回-1
insert(table: string, values: ValuesBucket): Promise<number> 向表中插入一行数据。
table: 插入数据的目标表名称
values: 插入到表中的数据行
Promise<number>: Promise对象。插入成功,返回行ID,否则返回-1
batchInsert(table: string, values: Array<ValuesBucket>, callback: AsyncCallback<number>):void 向表中插入一组数据
table: 插入数据的目标表名称
插入到表中的一组数据
callback: 回调函数。插入成功,返回插入的数据个数,否则返回-1
batchInsert(table: string, values: Array<ValuesBucket>):Promise<number> 向表中插入一组数据
table: 插入数据的目标表名称
插入到表中的一组数据
Promise<number>: Promise对象。插入成功,返回插入的数据个数,否则返回-1

注:表5-5中ValuesBucket是用于存储键值对的类型,其键为string类型,值类型可为ValueType|Uint8Array|null

const tableName = "USER";
const valueBacket = {
  "USERNAME": "Admin",
  "PASSWORD": "123456"
}
// insert callback形式
rdbStore.insert(tableName, valueBucket, (err, rowId) => {
  if (err) {
    Log.error(TAG, "Insert data failed, err: " + JSON.stringify(err));
    return;
  }
  Log.info(TAG, "Insert data successful, rowId = " + rowId);
})
// insert Promise形式
rdbStore.insert(tableName, valueBucket).then((rowId) => {
  Log.info(TAG, "Insert data successful, rowId = " + rowId);
}).catch((err) => {
  Log.error(TAG, "Insert data failed, err: " + JSON.stringify(err));
})

const valueBuckets = [{
  "USERNAME": "aaa",
  "PASSWORD": "123456"
}, {
  "USERNAME": "bbb",
  "PASSWORD": "123456"
}]
// batchInsert callback形式
rdbStore.batchInsert(tableName, valueBuckets, (err, count) => {
  if (err) {
    Log.error(TAG, "batchInsert data failed, err: " + JSON.stringify(err));
    return;
  }
  Log.info(TAG, "batchInsert data successful, count = " + count);
})
// batchInsert Promise形式
rdbStore.batchInsert(tableName, valueBuckets).then((count) => {
  Log.info(TAG, "batchInsert data successful, count = " + count);
}).catch((err) => {
  Log.error(TAG, "batchInsert data failed, err: " + JSON.stringify(err));
})

5.4.3 更新数据

RdbStore提供了根据RdbPredicates指定实例对象和根据DataSharePredicates指定实例对象两种方式更新数据表中的数据,两种方式均有callbackPromise形式,如表5-6所示。

RdbPredicatesDataSharePredicates均用于数据表中用来代表数据实体的性质、特征或者数据实体之间关系的词项,主要用于定义数据表的操作条件。如设置根据账号查找用户信息的条件,或者根据账号修改用户密码的条件。两者区别在于使用前者需要先指定操作的数据表名称,同时前者为分布式数据操作做了扩充。使用后者需要导入新模块import dataSharePredicates from '@ohos.data.dataSharePredicates';

表5-6 更新数据方法

方法名 描述
update(values: ValuesBucket, predicates: RdbPredicates, callback: AsyncCallback<number>):void 根据RdbPredicates的指定实例对象更新数据库中的数据。
values: 数据表中要更新的数据行
predicates: RdbPredicates的实例对象指定的更新条件
callback: 回调函数,返回受影响的行数
update(values: ValuesBucket, predicates: RdbPredicates):Promise<number> 根据RdbPredicates的指定实例对象更新数据库中的数据。
values: 数据表中要更新的数据行
predicates: RdbPredicates的实例对象指定的更新条件
Promise<number>: Promise对象,返回受影响的行数
update(table: string, values: ValuesBucket, predicates: dataSharePredicates.DataSharePredicates, callback: AsyncCallback<number>): void 根据DataSharePredicates的指定实例对象更新数据表的数据。
table: 更新数据表的名称
values: 数据表中要更新的数据行
predicates: DataSharePredicates的实例对象指定的更新条件
callback: 回调函数,返回受影响的行数
update(table: string, values: ValuesBucket, predicates: dataSharePredicates.DataSharePredicates): Promise<number> 根据DataSharePredicates的指定实例对象更新数据表的数据。
table: 更新数据表的名称
values: 数据表中要更新的数据行
predicates: DataSharePredicates的实例对象指定的更新条件
Promise<number>: Promise对象,返回受影响的行数
const tableName = "USER";
const valueBucket = {
  "USERNAME": "aaa",
  "PASSWORD": "123456789"
}

// RdbPredicates
let predicates = new relationalStore.RdbPredicates(tableName);
predicates.equalTo("USERNAME", "aaa");
// update callback形式
rdbStore.update(valueBucket, predicates, (err, rows) => {
  if (err) {
    Log.error(TAG, "Updated failed, err: " + JSON.stringify(err));
    return;
  }
  Log.info(TAG, "Updated row count: " + rows);
})
// update Promise形式
rdbStore.update(valueBucket, predicates).then((rows) => {
  Log.info(TAG, "Updated row count: " + rows);
}).catch((err) => {
  Log.error(TAG, "Updated failed, err: " + JSON.stringify(err));
})

// DataSharePredicates
let predicates = new dataSharePredicates.DataSharePredicates();
predicates.equalTo("USERNAME", "aaa");
// update callback形式
rdbStore.update(tableName, valueBucket, predicates, (err, rows) => {
  if (err) {
    Log.error(TAG, "Updated failed, err: " + JSON.stringify(err));
    return;
  }
  Log.info(TAG, "Updated row count: " + rows);
})
// update Promise形式
rdbStore.update(tableName, valueBucket, predicates).then((rows) => {
  Log.info(TAG, "Updated row count: " + rows);
}).catch((err) => {
  Log.error(TAG, "Updated failed, err: " + JSON.stringify(err));
})

5.4.4 查询数据

数据表数据的查询和更新相似,RdbStore也提供了RdbPredicatesDataSharePredicates两种方式,如表5-7所示。不同之处在于返回的结果不同,更新数据返回受影响的行数,查询数据返回的数据结果集ResultSet,关于结果集详细讲解将在下一节介绍。

表5-7 查询数据方法

方法名 描述
query(predicates: RdbPredicates, columns: Array<string>, callback: AsyncCallback<ResultSet>): void 根据RdbPredicates的指定实例对象条件查询数据表中的数据。
predicates: RdbPredicates的实例对象指定的查询条件
columns: 查询的列名称,为空则表示查询所有列
callback: 回调函数,操作成功,返回ResultSet对象
query(predicates: RdbPredicates, columns: Array<string>): Promise<ResultSet> 根据RdbPredicates的指定实例对象条件查询数据表中的数据。
predicates: RdbPredicates的实例对象指定的查询条件
columns: 查询的列名称,为空则表示查询所有列
Promise<ResultSet>: Promise对象,操作成功,返回ResultSet对象
query(table: string, predicates: dataSharePredicates.DataSharePredicates, columns: Array<string>, callback: AsyncCallback<ResultSet>): void 根据DataSharePredicates的指定实例对象条件查询数据表中的数据。
table: 查询数据表名称
predicates: DataSharePredicates的实例对象指定的查询条件
columns: 查询的列名称,为空则表示查询所有列
callback: 回调函数,操作成功,返回ResultSet对象
query(table: string, predicates: dataSharePredicates.DataSharePredicates, columns: Array<string>): Promise<ResultSet> 根据DataSharePredicates的指定实例对象条件查询数据表中的数据。
table: 查询数据表名称
predicates: DataSharePredicates的实例对象指定的查询条件
columns: 查询的列名称,为空则表示查询所有列
Promise<ResultSet>: Promise对象,操作成功,返回ResultSet对象
const tableName = "USER";
// RdbPredicates
let predicates = new relationalStore.RdbPredicates(tableName);
predicates.equalTo("USERNAME", "aaa");
// query callback形式
rdbStore.query(predicates, null, (err, resultSet) => {
  if (err) {
    Log.error(TAG, "Query failed, err: " + JSON.stringify(err));
    return;
  }
  Log.info(TAG, "Query successful.");
  Log.info(TAG, "ResultSet column count: " + resultSet.columnCount);
})
// query Promise形式
rdbStore.query(predicates, null).then((resultSet) => {
  Log.info(TAG, "Query successful.");
  Log.info(TAG, "ResultSet column count: " + resultSet.columnCoun
}).catch((err) => {
    Log.error(TAG, "Query failed, err: " + JSON.stringify(err));
})

// DataSharePredicates
let predicates = new dataSharePredicates.DataSharePredicates();
predicates.equalTo("USERNAME", "aaa");
// query callback形式
rdbStore.query(tableName, predicates, null, (err, resultSet) => {
  if (err) {
    Log.error(TAG, "Query failed, err: " + JSON.stringify(err));
    return;
  }
  Log.info(TAG, "Query successful.");
  Log.info(TAG, "ResultSet column count: " + resultSet.columnCount);
})
// query Promise形式
rdbStore.query(tableName, predicates, null).then((resultSet) => {
  Log.info(TAG, "Query successful.");
  Log.info(TAG, "ResultSet column count: " + resultSet.columnCount);
}).catch((err) => {
    Log.error(TAG, "Query failed, err: " + JSON.stringify(err));
})

5.4.5 删除数据

表5-8 删除数据方法

方法名 描述
delete(predicates: RdbPredicates, callback: AsyncCallback<number>):void 根据RdbPredicates指定实例对象从数据表中删除数据
predicates: RdbPredicates实例对象指定的删除条件
callback: 回调函数,返回受影响的行数
delete(predicates: RdbPredicates):Promise<number> 根据RdbPredicates指定实例对象从数据表中删除数据
predicates: RdbPredicates实例对象指定的删除条件
Promise<number>: Promise对象,返回受影响的行数
delete(table: string, predicates: dataSharePredicates.DataSharePredicates, callback: AsyncCallback<number>):void 根据DataSharePredicates指定实例对象从数据表中删除数据
table: 删除数据的数据表名称
predicates: DataSharePredicates实例对象指定的删除条件
callback: 回调函数,返回受影响的行数
delete(table: string, predicates: dataSharePredicates.DataSharePredicates):Promise<number> 根据DataSharePredicates指定实例对象从数据表中删除数据
table: 删除数据的数据表名称
predicates: DataSharePredicates实例对象指定的删除条件
Promise<number>: 回调函数,返回受影响的行数
const tableName = "USER";
// RdbPredicates
let predicates = new relationalStore.RdbPredicates(tableName);
predicates.equalTo("USERNAME", "aaa");
// delete callback
rdbStore.delete(predicates, (err, rows) => {
  if (err) {
    Log.error(TAG, "Delete failed, err: " + JSON.string(err));
    return;
  }
  Log.info(TAG, "Delete rows: " + rows);
})
// delete Promise
rdbStore.delete(predicates).then((rows) => {
  Log.info(TAG, "Delete rows: " + rows);
}).catch((err) => {
  Log.error(TAG, "Delete failed, err: " + JSON.string(err));
})

// DataSharePredicates
let predicates = new dataSharePredicates.DataSharePredicates();
predicates.equalTo("USERNAME", "aaa");
// delete callback
rdbStore.delete(tableName, predicates, (err, rows) => {
  if (err) {
    Log.error(TAG, "Delete failed, err: " + JSON.string(err));
    return;
  }
  Log.info(TAG, "Delete rows: " + rows);
})
// delete Promise
rdbStore.delete(tableName, predicates).then((rows) => {
  Log.info(TAG, "Delete rows: " + rows);
}).catch((err) => {
  Log.error(TAG, "Delete failed, err: " + JSON.string(err));
})

6 原生SQL操作数据表

RdbStore不仅提供了适用于增删改查简单易操作的接口方法,同时还支持原生SQL语句的操作。

  • querySql()方法支持使用指定SQL语句查询数据表中的数据
const sql = "select * from user";
rdbStore.querySql(sql).then((resultSet) => {
  Log.info(TAG, "Query successful.");
  Log.info(TAG, "ResultSet column count: " + resultSet.columnCount);
}).catch((err) => {
    Log.error(TAG, "Query failed, err: " + JSON.stringify(err));
})

当然RdbStore还提供了其他的方法,诸如在开始执行SQL语句之前开启事务的beginTransaction()方法、提交已执行的SQL语句的commit()方法、回滚已执行的SQL语句的rollBack()方法以及用于其他能力的方法。本节仅对RDB数据库的简单使用做了讲解,其中涉及到RdbPredicatesDataSharePredicatesResultSet相关的更多内容将在后续封装RDB工具类中详细介绍。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK