1 概述
关系型数据库(Relational Database, 以下简称 RDB)是一种基于关系模型来管理数据的数据库,是在 SQLite 基础上提供一套完整的对本地数据库进行管理的机制,为开发者提供无需编写原生 SQL 语句即可实现数据增、删、改、查等接口,同时开发者也可以直接运行原生 SQL 语句来满足复杂的场景需要。关系型数据库在应用卸载之后,才会被自动清除。
2 运作机制
RDB 对外提供通用的接口,底层使用 SQLite 作为持久化存储引擎,支持 SQLite 具有的所有数据库特性。SQLite 是一个进程内的库,具有自给自足、无服务、零配置、事务性特性的 SQL 数据库引擎。RDB 包括但不限于事务、索引、视图、触发器、外键、参数化查询和预编译 SQL 语句。
3 使用场景
通讯录
记事本
计算器历史记录
App 用户登录信息
App 主题
...
4 流程
5 详细步骤
RDB 对开发者提供的接口大部分为异步接口,均有callback和Promise两种返回形式,接下来将会一一介绍。
5.1 导入模块
import relationalStore from '@ohos.data.relationalStore';
复制代码
5.2 配置数据库相关信息
创建数据库时需要配置数据库相关信息,RDB 提供管理关系型数据库配置的StoreConfig接口,其参数如表 5-1 所示:
表 5-1 关系型数据库配置参数
表 5-2 数据库的安全级别枚举
const store_config = { name: "RdbSample.db", securityLevel: relationalStore.SecurityLevel.S4, encrypt: true}
复制代码
5.3 创建数据库
和 MySQL、Oracle 等数据库类似,在使用之前需要先创建数据库,RDB 提供了getRdbStore()方法用于创建数据库,该方法需要传入应用上下文Context和数据库配置信息StoreConfig两个参数,该方法有callback和Promise两种返回形式,如表 5-3 所示。表 5-3 数据库创建方法
// 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 语句,有callback和Promise两种形式,如表 5-4 所示。
表 5-4 创建数据表方法
注:表中的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 新增数据方法
注:表 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指定实例对象两种方式更新数据表中的数据,两种方式均有callback和Promise形式,如表 5-6 所示。
RdbPredicates和DataSharePredicates均用于数据表中用来代表数据实体的性质、特征或者数据实体之间关系的词项,主要用于定义数据表的操作条件。如设置根据账号查找用户信息的条件,或者根据账号修改用户密码的条件。两者区别在于使用前者需要先指定操作的数据表名称,同时前者为分布式数据操作做了扩充。使用后者需要导入新模块import dataSharePredicates from '@ohos.data.dataSharePredicates';
表 5-6 更新数据方法
const tableName = "USER";const valueBucket = { "USERNAME": "aaa", "PASSWORD": "123456789"}
// RdbPredicateslet 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));})
// DataSharePredicateslet 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也提供了RdbPredicates和DataSharePredicates两种方式,如表 5-7 所示。不同之处在于返回的结果不同,更新数据返回受影响的行数,查询数据返回的数据结果集ResultSet,关于结果集详细讲解将在下一节介绍。
表 5-7 查询数据方法
const tableName = "USER";// RdbPredicateslet 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));})
// DataSharePredicateslet 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 删除数据方法
const tableName = "USER";// RdbPredicateslet predicates = new relationalStore.RdbPredicates(tableName);predicates.equalTo("USERNAME", "aaa");// delete callbackrdbStore.delete(predicates, (err, rows) => { if (err) { Log.error(TAG, "Delete failed, err: " + JSON.string(err)); return; } Log.info(TAG, "Delete rows: " + rows);})// delete PromiserdbStore.delete(predicates).then((rows) => { Log.info(TAG, "Delete rows: " + rows);}).catch((err) => { Log.error(TAG, "Delete failed, err: " + JSON.string(err));})
// DataSharePredicateslet predicates = new dataSharePredicates.DataSharePredicates();predicates.equalTo("USERNAME", "aaa");// delete callbackrdbStore.delete(tableName, predicates, (err, rows) => { if (err) { Log.error(TAG, "Delete failed, err: " + JSON.string(err)); return; } Log.info(TAG, "Delete rows: " + rows);})// delete PromiserdbStore.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 语句的操作。
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));})
复制代码
7 小节
当然RdbStore还提供了其他的方法,诸如在开始执行 SQL 语句之前开启事务的beginTransaction()方法、提交已执行的 SQL 语句的commit()方法、回滚已执行的 SQL 语句的rollBack()方法以及用于其他能力的方法。本节仅对 RDB 数据库的简单使用做了讲解,其中涉及到RdbPredicates、DataSharePredicates、ResultSet相关的更多内容将在后续封装 RDB 工具类中详细介绍。
评论