1# 关系型数据库开发指导 2 3## 场景介绍 4 5关系型数据库是在SQLite基础上实现的本地数据操作机制,提供给用户无需编写原生SQL语句就能进行数据增删改查的方法,同时也支持原生SQL语句操作。 6 7 8## 接口说明 9以下是关系型数据库的常用接口说明,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以Promise形式为例,更多接口及使用方式请见[关系型数据库](../reference/apis/js-apis-data-rdb.md)。 10 11### 数据库的创建和删除 12 13关系型数据库提供了数据库创建方式,以及对应的删除接口,涉及的API如下所示。 14 15**表1** 数据库创建和删除API 16 17| 接口名 | 描述 | 18| -------- | -------- | 19|getRdbStore(config: StoreConfig, version: number): Promise<RdbStore> | 获得一个相关的RdbStore,操作关系型数据库,用户可以根据自己的需求配置RdbStore的参数,然后通过RdbStore调用相关接口可以执行相关的数据操作,使用Promise异步回调。<br/>-config:与此RDB存储相关的数据库配置。<br/>-version:数据库版本。 | 20| deleteRdbStore(name: string): Promise<void> | 使用指定的数据库文件配置删除数据库,使用Promise异步回调。<br/>-name:数据库名称。 | 21 22### 数据库的增删改查 23 24关系型数据库提供对本地数据增删改查操作的能力,相关API如下所示。 25 26- **新增** 27 28 关系型数据库提供了插入数据的接口,通过ValuesBucket输入要存储的数据,通过返回值判断是否插入成功,插入成功时返回最新插入数据所在的行号,失败时则返回-1。 29 30 **表2** 数据库插入API 31 32 | 类名 | 接口名 | 描述 | 33 | -------- | -------- | -------- | 34 | RdbStore | insert(name: string, values: ValuesBucket): Promise<number> | 向目标表中插入一行数据,使用Promise异步回调。<br>如果操作成功,返回行ID;否则返回-1。<br/>-name:指定的目标表名。<br/>-values:表示要插入到表中的数据行。 | 35 36- **更新** 37 38 调用更新接口,传入要更新的数据,并通过RdbPredicates指定更新条件。该接口的返回值表示更新操作影响的行数。如果更新失败,则返回0。 39 40 **表3** 数据库更新API 41 42 | 类名 | 接口名 | 描述 | 43 | -------- | -------- | -------- | 44 | RdbStore | update(values: ValuesBucket, rdbPredicates: RdbPredicates): Promise\<number> | 根据RdbPredicates的指定实例对象更新数据库中的数据,使用Promise异步回调。<br>返回受影响的行数。<br/>-values:以ValuesBucket存储的要更新的数据。<br/>-rdbPredicates:表示RdbPredicates的实例对象指定的更新条件。 | 45 46- **删除** 47 48 调用删除接口,通过RdbPredicates指定删除条件。该接口的返回值表示删除的数据行数,可根据此值判断是否删除成功。如果删除失败,则返回0。 49 50 **表4** 数据库删除API 51 52 | 类名 | 接口名 | 描述 | 53 | -------- | -------- | -------- | 54 | RdbStore | delete(rdbPredicates: RdbPredicates): Promise\<number> | 根据rdbPredicates的指定实例对象从数据库中删除数据,使用Promise异步回调。<br>返回受影响的行数。<br/>-rdbPredicates:RdbPredicates的实例对象指定的删除条件。 | 55 56- **查询** 57 58 关系型数据库提供了两种查询数据的方式: 59 60 - 直接调用查询接口。使用该接口,会将包含查询条件的谓词自动拼接成完整的SQL语句进行查询操作,无需用户传入原生的SQL语句。 61 - 执行原生的SQL语句进行查询操作。 62 63 **表5** 数据库查询API 64 65 | 类名 | 接口名 | 描述 | 66 | -------- | -------- | -------- | 67 | RdbStore | query(rdbPredicates: RdbPredicates, columns: Array): Promise<ResultSet> | 根据指定条件查询数据库中的数据,使用Promise异步回调。<br/>-rdbPredicates:表示RdbPredicates的实例对象指定的查询条件。<br/>-columns:表示要查询的列。如果值为空,则查询应用于所有列。 | 68 | RdbStore | querySql(sql: string, bindArgs?: Array<ValueType>): Promise<ResultSet> | 根据指定SQL语句查询数据库中的数据,使用Promise异步回调。<br/>-sql:指定要查询的SQL语句。<br/>-bindArgs:SQL语句中参数的值。 | 69 70### 数据库谓词的使用 71 72关系型数据库提供了用于设置数据库操作条件的谓词RdbPredicates,该类确定RDB中条件表达式的值是true还是false。 73 74以下列举几个常用谓词,更多谓词的使用请见[关系型数据库谓词](../reference/apis/js-apis-data-rdb.md#rdbpredicates)。 75 76**表6** 数据库谓词API 77 78| 类名 | 接口名 | 描述 | 79| -------- | -------- | -------- | 80| RdbPredicates | equalTo(field: string, value: ValueType): RdbPredicates | 配置谓词以匹配数据字段为ValueType且值等于指定值的字段。<br/>-field:数据库表中的列名。<br/>-value:指示要与谓词匹配的值。<br/>-RdbPredicates:返回与指定字段匹配的谓词。 | 81| RdbPredicates | notEqualTo(field: string, value: ValueType): RdbPredicates | 配置谓词以匹配数据字段为ValueType且值不等于指定值的字段。<br/>-field:数据库表中的列名。<br/>-value:指示要与谓词匹配的值。<br/>-RdbPredicates:返回与指定字段匹配的谓词。 | 82| RdbPredicates | or(): RdbPredicates | 将或条件添加到谓词中。<br/>-RdbPredicates:返回带有或条件的谓词。 | 83| RdbPredicates | and(): RdbPredicates | 向谓词添加和条件。<br/>-RdbPredicates:返回带有和条件的谓词。 | 84| RdbPredicates | contains(field: string, value: string): RdbPredicats | 配置谓词以匹配数据字段为String且value包含指定值的字段。<br/>-field:数据库表中的列名。<br/>-value:指示要与谓词匹配的值。<br/>-RdbPredicates:返回带有包含条件的谓词。 | 85 86 87### 查询结果集的使用 88 89关系型数据库提供了查询返回的结果集ResultSet,其指向查询结果中的一行数据,供用户对查询结果进行遍历和访问。 90 91更多结果集的接口使用,请见[结果集](../reference/apis/js-apis-data-resultset.md)。 92 93> **须知:** 94> **结果集使用完后,请一定要调用close方法显式关闭。** 95 96**表7** 结果集API 97 98| 类名 | 接口名 | 描述 | 99| -------- | -------- | -------- | 100| ResultSet | goToFirstRow(): boolean | 将结果集移动到第一行。 | 101| ResultSet | getString(columnIndex:number): string | 获取当前行指定列的值,以String类型返回。 | 102| ResultSet | getBlob(columnIndex:number): Uint8Array | 获取当前行指定列的值,以字节数组形式返回。 | 103| ResultSet | getDouble(columnIndex:number): number | 获取当前行指定列的值,以double型返回。 | 104| ResultSet | getLong(columnIndex:number): number | 获取当前行指定列的值,以Long形式返回。 | 105| ResultSet | close(): void | 关闭结果集。 | 106 107 108 109### 设置分布式列表 110 111**设置分布式列表** 112 113**表8** 设置分布式列表 114 115| 类名 | 接口名 | 描述 | 116| -------- | -------- | -------- | 117| RdbStore | setDistributedTables(tables: Array\<string>): Promise\<void>; | 设置分布式列表,使用Promise异步回调。<br/>-tables:要设置的分布式列表表名。 | 118 119**根据本地表名获取指定远程设备的分布式表名** 120 121用户根据本地表名获取指定远程设备的分布式表名。在查询远程设备数据库时,需要使用分布式表名。 122 123**表9** 根据本地表名获取指定远程设备的分布式表名 124 125| 类名 | 接口名 | 描述 | 126| -------- | -------- | -------- | 127| RdbStore | obtainDistributedTableName(device: string, table: string): Promise\<string>; | 根据本地表名获取指定远程设备的分布式表名。在查询远程设备数据库时,需要使用分布式表名,使用Promise异步回调。<br/>-device:远程设备。<br/>-table:本地表名。 | 128 129**在设备之间同步数据** 130 131**表10** 在设备之间同步数据 132 133| 类名 | 接口名 | 描述 | 134| -------- | -------- | -------- | 135| RdbStore | sync(mode: SyncMode, predicates: RdbPredicates): Promise<Array<[string, number]>>;| 在设备之间同步数据,使用Promise异步回调。<br/>-mode:指同步模式。SYNC_MODE_PUSH 表示数据从本地设备推送到远程设备;SYNC_MODE_PULL 表示数据从远程设备拉至本地设备。<br/>-predicates:约束同步数据和设备。<br>-string:设备ID;number:每个设备同步状态,0表示成功,其他值表示失败。 | 136 137**注册数据库的观察者** 138 139**表11** 注册数据库的观察者 140 141| 类名 | 接口名 | 描述 | 142| -------- | -------- | -------- | 143| RdbStore |on(event: 'dataChange', type: SubscribeType, observer: Callback<Array\<string>>): void;| 注册数据库的观察者。当分布式数据库中的数据发生更改时,将调用回调。<br/>-type:指在{@code SubscribeType}中定义的订阅类型;SUBSCRIBE_TYPE_REMOTE 订阅远程数据更改。<br/>-observer:指分布式数据库中数据更改事件的观察者。 | 144 145**从数据库中删除指定类型的指定观察者** 146 147**表12** 从数据库中删除指定类型的指定观察者 148 149| 类名 | 接口名 | 描述 | 150| -------- | -------- | -------- | 151| RdbStore |off(event:'dataChange', type: SubscribeType, observer: Callback<Array\<string>>): void;| 从数据库中删除指定类型的指定观察者,结果以callback形式返回。<br/>-type:指在{@code SubscribeType}中定义的订阅类型;SUBSCRIBE_TYPE_REMOTE 订阅远程数据更改。<br/>-observer:指已注册的数据更改观察者。 | 152 153 154## 开发步骤 155 1561. 创建数据库。 157 1. 配置数据库相关信息,包括数据库的名称、存储模式、是否为只读模式等。 158 2. 初始化数据库表结构和相关数据。 159 3. 创建数据库。 160 161 示例代码如下: 162 163 ```js 164 import data_rdb from '@ohos.data.rdb' 165 166 const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "name TEXT NOT NULL, " + "age INTEGER, " + "salary REAL, " + "blobType BLOB)"; 167 const STORE_CONFIG = {name: "rdbstore.db"} 168 data_rdb.getRdbStore(STORE_CONFIG, 1, function (err, rdbStore) { 169 rdbStore.executeSql(CREATE_TABLE_TEST ) 170 console.info('create table done.') 171 }) 172 ``` 173 1742. 插入数据。 175 1. 构造要插入的数据,以ValuesBucket形式存储。 176 2. 调用关系型数据库提供的插入接口。 177 178 示例代码如下: 179 180 ```js 181 var u8 = new Uint8Array([1, 2, 3]) 182 const valueBucket = {"name": "Tom", "age": 18, "salary": 100.5, "blobType": u8} 183 let insertPromise = rdbStore.insert("test", valueBucket) 184 ``` 185 1863. 查询数据。 187 1. 构造用于查询的谓词对象,设置查询条件。 188 2. 调用查询接口查询数据。 189 3. 调用结果集接口,返回查询结果。 190 191 示例代码如下: 192 193 ```js 194 let predicates = new data_rdb.RdbPredicates("test"); 195 predicates.equalTo("name", "Tom") 196 let promisequery = rdbStore.query(predicates) 197 promisequery.then((resultSet) => { 198 resultSet.goToFirstRow() 199 const id = resultSet.getLong(resultSet.getColumnIndex("id")) 200 const name = resultSet.getString(resultSet.getColumnIndex("name")) 201 const age = resultSet.getLong(resultSet.getColumnIndex("age")) 202 const salary = resultSet.getDouble(resultSet.getColumnIndex("salary")) 203 const blobType = resultSet.getBlob(resultSet.getColumnIndex("blobType")) 204 resultSet.close() 205 }) 206 ``` 207 2084. 设置分布式同步表。 209 1. 数据库调用接口设置分布式同步列表。 210 2. 判断是否设置成功。 211 212 示例代码如下: 213 214 ```js 215 let promise = rdbStore.setDistributedTables(["test"]) 216 promise.then(() => { 217 console.info("setDistributedTables success.") 218 }).catch((err) => { 219 console.info("setDistributedTables failed.") 220 }) 221 ``` 222 223 5. 分布式数据同步。 224 1. 构造用于同步分布式表的谓词对象,指定组网内的远程设备。 225 2. 调用同步数据的接口 。 226 3. 判断是否数据同步成功。 227 228 示例代码如下: 229 230 ```js 231 let predicate = new data_rdb.RdbPredicates('test') 232 predicate.inDevices(['12345678abcde']) 233 let promise = rdbStore.sync(rdb.SyncMode.SYNC_MODE_PUSH, predicate) 234 promise.then((result) => { 235 console.log('sync done.') 236 for (let i = 0; i < result.length; i++) { 237 console.log('device=' + result[i][0] + ' status=' + result[i][1]) 238 } 239 }).catch((err) => { 240 console.log('sync failed') 241 }) 242 ``` 243 2446. 分布式数据订阅。 245 1. 调用分布式数据订阅接口,注册数据库的观察者。 246 2. 当分布式数据库中的数据发生更改时,将调用回调。 247 248 示例代码如下: 249 250 ```js 251 function storeObserver(devices) { 252 for (let i = 0; i < devices.length; i++) { 253 console.log('device=' + devices[i] + ' data changed') 254 } 255 } 256 try { 257 rdbStore.on('dataChange', rdb.SubscribeType.SUBSCRIBE_TYPE_REMOTE, storeObserver) 258 } catch (err) { 259 console.log('register observer failed') 260 } 261 ``` 262 2637. 跨设备查询。 264 1. 根据本地表名获取指定远程设备的分布式表名。 265 2. 调用结果集接口,返回查询结果。 266 267 示例代码如下: 268 269 ```js 270 let tableName = rdbStore.obtainDistributedTableName(deviceId, "test"); 271 let resultSet = rdbStore.querySql("SELECT * FROM " + tableName) 272 ``` 273## 相关实例 274针对关系型数据库开发,有以下相关实例可供参考: 275- [`DistributedRdb`:分布式关系型数据库(eTS)(API8)(Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/samples_monthly_0730/data/DistributedRdb) 276- [关系型数据库(JS)(API8)](https://gitee.com/openharmony/codelabs/tree/master/Data/JSRelationshipData) 277