1# 关系型数据库开发指导 2 3## 场景介绍 4 5关系型数据库是在SQLite基础上实现的本地数据操作机制,提供给用户无需编写原生SQL语句就能进行数据增删改查的方法,同时也支持原生SQL语句操作。 6 7 8## 接口说明 9 10以下是关系型数据库的常用接口说明,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以Promise形式为例,更多接口及使用方式请见[关系型数据库](../reference/apis/js-apis-data-relationalStore.md)。 11 12### 数据库的创建和删除 13 14关系型数据库提供了数据库创建方式,以及对应的删除接口,涉及的API如下所示。 15 16**表1** 数据库创建和删除API 17 18| 接口名 | 描述 | 19| ------------------------------------------------------------ | ------------------------------------------------------------ | 20| getRdbStore(context: Context, config: StoreConfig): Promise<RdbStore> | 获得一个相关的RdbStore,操作关系型数据库,用户可以根据自己的需求配置RdbStore的参数,然后通过RdbStore调用相关接口可以执行相关的数据操作,使用Promise异步回调。<br/>-context:应用上下文。<br/>-config:与此RDB存储相关的数据库配置。 | 21| deleteRdbStore(context: Context, name: string): Promise<void> | 使用指定的数据库文件配置删除数据库,使用Promise异步回调。<br/>-context:应用上下文。<br/>-name:数据库名称。 | 22 23### 数据库的增删改查 24 25关系型数据库提供对本地数据增删改查操作的能力,相关API如下所示。 26 27- **新增** 28 29 关系型数据库提供了插入数据的接口,通过ValuesBucket输入要存储的数据,通过返回值判断是否插入成功,插入成功时返回最新插入数据所在的行号,失败时则返回-1。 30 31 **表2** 数据库插入API 32 33 34 | 类名 | 接口名 | 描述 | 35 | ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 36 | RdbStore | insert(table: string, values: ValuesBucket): Promise<number> | 向目标表中插入一行数据,使用Promise异步回调。<br>如果操作成功,返回行ID;否则返回-1。<br/>-table:指定的目标表名。<br/>-values:表示要插入到表中的数据行。 | 37 38- **更新** 39 40 调用更新接口,传入要更新的数据,并通过RdbPredicates指定更新条件。该接口的返回值表示更新操作影响的行数。如果更新失败,则返回0。 41 42 **表3** 数据库更新API 43 44 45 | 类名 | 接口名 | 描述 | 46 | ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 47 | RdbStore | update(values: ValuesBucket, predicates: RdbPredicates): Promise<number> | 根据RdbPredicates的指定实例对象更新数据库中的数据,使用Promise异步回调。<br>返回受影响的行数。<br/>-values:以ValuesBucket存储的要更新的数据。<br/>-predicates:表示RdbPredicates的实例对象指定的更新条件。 | 48 49- **删除** 50 51 调用删除接口,通过RdbPredicates指定删除条件。该接口的返回值表示删除的数据行数,可根据此值判断是否删除成功。如果删除失败,则返回0。 52 53 **表4** 数据库删除API 54 55 56 | 类名 | 接口名 | 描述 | 57 | ---------- | ---------------------------------------------------------- | ------------------------------------------------------------ | 58 | RdbStore | delete(predicates: RdbPredicates): Promise<number> | 根据RdbPredicates的指定实例对象从数据库中删除数据,使用Promise异步回调。<br>返回受影响的行数。 <br/>-predicates:RdbPredicates的实例对象指定的删除条件。 | 59 60- **查询** 61 62 关系型数据库提供了两种查询数据的方式: 63 64 - 直接调用查询接口。使用该接口,会将包含查询条件的谓词自动拼接成完整的SQL语句进行查询操作,无需用户传入原生的SQL语句。 65 - 执行原生的SQL语句进行查询操作。 66 67 **表5** 数据库查询API 68 69 | 类名 | 接口名 | 描述 | 70 | ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 71 | RdbStore | query(predicates: RdbPredicates, columns?: Array<string>): Promise<ResultSet> | 根据指定条件查询数据库中的数据,使用Promise异步回调。<br/>-predicates:表示RdbPredicates的实例对象指定的查询条件。<br/>-columns:表示要查询的列。如果值为空,则查询应用于所有列。 | 72 | RdbStore | querySql(sql: string, bindArgs?: Array<ValueType>): Promise<ResultSet> | 根据指定SQL语句查询数据库中的数据,使用Promise异步回调。<br/>-sql:指定要查询的SQL语句。<br/>-bindArgs:SQL语句中参数的值。 | 73 | RdbStore | remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array<string>): Promise<ResultSet> | 根据指定条件查询指定远程设备数据库中的数据。使用Promise异步回调。<br/>-device:指定远程查询的设备networkId。<br/>-table:指定远程查询的表名。<br/>-predicates:表示RdbPredicates的实例对象,指定查询的条件。<br/>-columns:表示要查询的列。如果值为空,则查询应用于所有列。 | 74 75### 数据库谓词的使用 76 77关系型数据库提供了用于设置数据库操作条件的谓词RdbPredicates,该类确定RDB中条件表达式的值是true还是false。 78 79以下列举几个常用谓词,更多谓词的使用请见[关系型数据库谓词](../reference/apis/js-apis-data-relationalStore.md#rdbpredicates)。 80 81**表6** 数据库谓词API 82 83| 类名 | 接口名 | 描述 | 84| --------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 85| RdbPredicates | equalTo(field: string, value: ValueType): RdbPredicates | 配置谓词以匹配数据字段为ValueType且值等于指定值的字段。<br/>-field:数据库表中的列名。<br/>-value:指示要与谓词匹配的值。<br/>-RdbPredicates:返回与指定字段匹配的谓词。 | 86| RdbPredicates | notEqualTo(field: string, value: ValueType): RdbPredicates | 配置谓词以匹配数据字段为ValueType且值不等于指定值的字段。<br/>-field:数据库表中的列名。<br/>-value:指示要与谓词匹配的值。<br/>-RdbPredicates:返回与指定字段匹配的谓词。 | 87| RdbPredicates | or(): RdbPredicates | 将或条件添加到谓词中。<br/>-RdbPredicates:返回带有或条件的谓词。 | 88| RdbPredicates | and(): RdbPredicates | 向谓词添加和条件。<br/>-RdbPredicates:返回带有和条件的谓词。 | 89| RdbPredicates | contains(field: string, value: string): RdbPredicates | 配置谓词以匹配数据字段为String且value包含指定值的字段。<br/>-field:数据库表中的列名。<br/>-value:指示要与谓词匹配的值。<br/>-RdbPredicates:返回带有包含条件的谓词。 | 90 91 92### 查询结果集的使用 93 94关系型数据库提供了查询返回的结果集ResultSet,其指向查询结果中的一行数据,供用户对查询结果进行遍历和访问。 95 96更多结果集的接口使用,请见[结果集](../reference/apis/js-apis-data-relationalStore.md#resultset)。 97 98> **须知:** 99> **结果集使用完后,请一定要调用close方法显式关闭。** 100 101**表7** 结果集API 102 103| 类名 | 接口名 | 描述 | 104| ----------- | ---------------------------------------- | ------------------------------------------ | 105| ResultSet | goToFirstRow(): boolean | 将结果集移动到第一行。 | 106| ResultSet | getString(columnIndex: number): string | 获取当前行指定列的值,以String类型返回。 | 107| ResultSet | getBlob(columnIndex: number): Uint8Array | 获取当前行指定列的值,以字节数组形式返回。 | 108| ResultSet | getDouble(columnIndex: number): number | 获取当前行指定列的值,以double型返回。 | 109| ResultSet | getLong(columnIndex: number): number | 获取当前行指定列的值,以Long形式返回。 | 110| ResultSet | close(): void | 关闭结果集。 | 111 112 113 114### 设置分布式列表 115 116> **说明:** 117> 118> - 在使用RdbStore的setDistributedTables、obtainDistributedTableName、sync、on、off接口时,需要请求相应的权限:ohos.permission.DISTRIBUTED_DATASYNC。 119> - 使用分布式列表前,需要先建立设备间组网,具体接口及使用可见[设备管理](../reference/apis/js-apis-device-manager.md)。 120 121**设置分布式列表** 122 123**表8** 设置分布式列表 124 125| 类名 | 接口名 | 描述 | 126| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 127| RdbStore | setDistributedTables(tables: Array\<string>): Promise\<void> | 设置分布式列表,使用Promise异步回调。<br/>-tables:要设置的分布式列表表名。 | 128 129**根据本地表名获取指定远程设备的分布式表名** 130 131用户根据本地表名获取指定远程设备的分布式表名。在查询远程设备数据库时,需要使用分布式表名。 132 133**表9** 根据本地表名获取指定远程设备的分布式表名 134 135| 类名 | 接口名 | 描述 | 136| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 137| RdbStore | obtainDistributedTableName(device: string, table: string): Promise\<string> | 根据本地表名获取指定远程设备的分布式表名。在查询远程设备数据库时,需要使用分布式表名,使用Promise异步回调。<br/>-device:远程设备。<br/>-table:本地表名。 | 138 139**在设备之间同步数据** 140 141**表10** 在设备之间同步数据 142 143| 类名 | 接口名 | 描述 | 144| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 145| 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表示成功,其他值表示失败。 | 146 147**注册数据库的观察者** 148 149**表11** 注册数据库的观察者 150 151| 类名 | 接口名 | 描述 | 152| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 153| RdbStore | on(event: 'dataChange', type: SubscribeType, observer: Callback\<Array\<string>>): void | 注册数据库的观察者。当分布式数据库中的数据发生更改时,将调用回调。<br/>-type:订阅类型;SUBSCRIBE_TYPE_REMOTE 订阅远程数据更改。<br/>-observer:指分布式数据库中数据更改事件的观察者。 | 154 155**从数据库中删除指定类型的指定观察者** 156 157**表12** 从数据库中删除指定类型的指定观察者 158 159| 类名 | 接口名 | 描述 | 160| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 161| RdbStore | off(event:'dataChange', type: SubscribeType, observer: Callback\<Array\<string>>): void; | 从数据库中删除指定类型的指定观察者,使用callback异步回调。<br/>-type:订阅类型;SUBSCRIBE_TYPE_REMOTE 订阅远程数据更改。<br/>-observer:指已注册的数据更改观察者。 | 162 163### 数据库的备份和恢复 164 165**备份** 166 167**表13** 备份数据库 168 169| 类名 | 接口名 | 描述 | 170| ---------- | --------------------------------------------- | ------------------------------------------------------------ | 171| RdbStore | backup(destName: string): Promise<void> | 以指定名称备份数据库,使用Promise异步回调。<br/>-destName:指定数据库的备份文件名。 | 172 173**恢复** 174 175**表14** 恢复数据库 176 177| 类名 | 接口名 | 描述 | 178| ---------- | --------------------------------------------- | ------------------------------------------------------------ | 179| RdbStore | restore(srcName: string): Promise<void> | 从指定的数据库备份文件恢复数据库,使用Promise异步回调。<br/>-srcName:指定数据库的备份文件名。 | 180 181### 事务 182 183**表15** 事务 184 185| 类名 | 接口名 | 描述 | 186| -------- | ----------------------- | --------------------------------- | 187| RdbStore | beginTransaction(): void | 在开始执行SQL语句之前,开始事务。 | 188| RdbStore | commit(): void | 提交已执行的SQL语句。 | 189| RdbStore | rollBack(): void | 回滚已经执行的SQL语句。 | 190 191## 开发步骤 192 1931. 创建数据库。 194 195 (1) 配置数据库相关信息,包括数据库的名称、存储模式、是否为只读模式等。 196 197 (2) 初始化数据库表结构和相关数据。 198 199 (3) 创建数据库。 200 201 FA模型示例: 202 203 ```js 204 import relationalStore from '@ohos.data.relationalStore' 205 import featureAbility from '@ohos.ability.featureAbility' 206 207 var store; 208 209 // 获取context 210 let context = featureAbility.getContext(); 211 212 const STORE_CONFIG = { 213 name: "RdbTest.db", 214 securityLevel: relationalStore.SecurityLevel.S1 215 }; 216 217 relationalStore.getRdbStore(context, STORE_CONFIG, function (err, rdbStore) { 218 store = rdbStore; 219 if (err) { 220 console.error(`Get RdbStore failed, err: ${err}`); 221 return; 222 } 223 console.info(`Get RdbStore successfully.`); 224 }) 225 ``` 226 Stage模型示例: 227 ```ts 228 import relationalStore from '@ohos.data.relationalStore' 229 import UIAbility from '@ohos.app.ability.UIAbility' 230 231 class EntryAbility extends UIAbility { 232 onWindowStageCreate(windowStage) { 233 var store; 234 const STORE_CONFIG = { 235 name: "RdbTest.db", 236 securityLevel: relationalStore.SecurityLevel.S1 237 }; 238 239 relationalStore.getRdbStore(this.context, STORE_CONFIG, function (err, rdbStore) { 240 store = rdbStore; 241 if (err) { 242 console.error(`Get RdbStore failed, err: ${err}`); 243 return; 244 } 245 console.info(`Get RdbStore successfully.`); 246 }) 247 } 248 } 249 ``` 250 2512. 插入数据。 252 253 (1) 构造要插入的数据,以ValuesBucket形式存储。 254 255 (2) 调用关系型数据库提供的插入接口。 256 257 示例代码如下: 258 259 ```js 260 let u8 = new Uint8Array([1, 2, 3]); 261 const valueBucket = { "name": "Tom", "age": 18, "salary": 100.5, "blobType": u8 }; 262 let insertPromise = store.insert("test", valueBucket); 263 ``` 264 265 ```js 266 //使用事务插入数据 267 try { 268 store.beginTransaction(); 269 let u8 = new Uint8Array([1, 2, 3]); 270 const valueBucket = { "name": "Tom", "age": 18, "salary": 100.5, "blobType": u8 }; 271 let promise = store.insert("test", valueBucket); 272 promise.then(() => { 273 store.commit(); 274 }) 275 } catch (err) { 276 console.error(`Transaction failed, err: ${err}`); 277 store.rollBack(); 278 } 279 ``` 280 2813. 查询数据。 282 283 (1) 构造用于查询的谓词对象,设置查询条件。 284 285 (2) 调用查询接口查询数据。 286 287 (3) 调用结果集接口,返回查询结果。 288 289 示例代码如下: 290 291 ```js 292 let predicates = new relationalStore.RdbPredicates("test"); 293 predicates.equalTo("name", "Tom"); 294 let promisequery = store.query(predicates); 295 promisequery.then((resultSet) => { 296 resultSet.goToFirstRow(); 297 const id = resultSet.getLong(resultSet.getColumnIndex("id")); 298 const name = resultSet.getString(resultSet.getColumnIndex("name")); 299 const age = resultSet.getLong(resultSet.getColumnIndex("age")); 300 const salary = resultSet.getDouble(resultSet.getColumnIndex("salary")); 301 const blobType = resultSet.getBlob(resultSet.getColumnIndex("blobType")); 302 resultSet.close(); 303 }) 304 ``` 305 3064. 设置分布式同步表。 307 308 (1) 权限配置文件中增加以下配置。 309 310 ```json 311 "requestPermissions": 312 { 313 "name": "ohos.permission.DISTRIBUTED_DATASYNC" 314 } 315 ``` 316 317 (2) 获取应用权限。 318 319 (3) 数据库调用接口设置分布式同步列表。 320 321 (4) 判断是否设置成功。 322 323 示例代码如下: 324 325 ```js 326 let context = featureAbility.getContext(); 327 context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) { 328 console.info(`result.requestCode=${result.requestCode}`); 329 }) 330 let promise = store.setDistributedTables(["test"]); 331 promise.then(() => { 332 console.info(`setDistributedTables success.`); 333 }).catch((err) => { 334 console.error(`setDistributedTables failed, ${err}`); 335 }) 336 ``` 337 3385. 分布式数据同步。 339 340 (1) 构造用于同步分布式表的谓词对象,指定组网内的远程设备。 341 342 (2) 调用同步数据的接口。 343 344 (3) 判断数据同步是否成功。 345 346 示例代码如下: 347 348 ```js 349 let predicate = new relationalStore.RdbPredicates('test'); 350 predicate.inDevices(['12345678abcde']); 351 let promise = store.sync(relationalStore.SyncMode.SYNC_MODE_PUSH, predicate); 352 promise.then((result) => { 353 console.info(`sync done.`); 354 for (let i = 0; i < result.length; i++) { 355 console.info(`device=${result[i][0]}, status=${result[i][1]}`); 356 } 357 }).catch((err) => { 358 console.error(`sync failed, err: ${err}`); 359 }) 360 ``` 361 3626. 分布式数据订阅。 363 364 (1) 调用分布式数据订阅接口,注册数据库的观察者。 365 366 (2) 当分布式数据库中的数据发生更改时,将调用回调。 367 368 示例代码如下: 369 370 ```js 371 function storeObserver(devices) { 372 for (let i = 0; i < devices.length; i++) { 373 console.info(`device= ${devices[i]} data changed`); 374 } 375 } 376 377 try { 378 store.on('dataChange', relationalStore.SubscribeType.SUBSCRIBE_TYPE_REMOTE, storeObserver); 379 } catch (err) { 380 console.error(`register observer failed, err: ${err}`); 381 } 382 ``` 383 3847. 跨设备查询。 385 386 (1) 根据本地表名获取指定远程设备的分布式表名。 387 388 (2) 调用结果集接口,返回查询结果。 389 390 示例代码如下: 391 392 ```js 393 import deviceManager from '@ohos.distributedHardware.deviceManager' 394 395 let deviceIds = []; 396 deviceManager.createDeviceManager('bundleName', (err, value) => { 397 if (!err) { 398 let devManager = value; 399 if (devManager != null) { 400 // 获取deviceIds 401 let devices = devManager.getTrustedDeviceListSync(); 402 for (let i = 0; i < devices.length; i++) { 403 deviceIds[i] = devices[i].deviceId; 404 } 405 } 406 } 407 }) 408 409 let tableName = store.obtainDistributedTableName(deviceIds[0], "test"); 410 let resultSet = store.querySql("SELECT * FROM " + tableName); 411 ``` 412 4138. 远程查询。 414 415 (1) 构造用于查询分布式表的谓词对象,指定组网内的远程分布式表名和设备。 416 417 (2) 调用结果集接口,返回查询结果。 418 419 示例代码如下: 420 421 ```js 422 let rdbPredicate = new relationalStore.RdbPredicates('employee'); 423 predicates.greaterThan("id", 0) ; 424 let promiseQuery = store.remoteQuery('12345678abcde', 'employee', rdbPredicate); 425 promiseQuery.then((resultSet) => { 426 while (resultSet.goToNextRow()) { 427 let idx = resultSet.getLong(0); 428 let name = resultSet.getString(1); 429 let age = resultSet.getLong(2); 430 console.info(`indx: ${idx}, name: ${name}, age: ${age}`); 431 } 432 resultSet.close(); 433 }).catch((err) => { 434 console.error(`failed to remoteQuery, err: ${err}`); 435 }) 436 ``` 437 4389. 数据库的备份和恢复。 439 440 (1) 调用数据库的备份接口,备份当前数据库文件。 441 442 示例代码如下: 443 444 ```js 445 let promiseBackup = store.backup("dbBackup.db"); 446 promiseBackup.then(() => { 447 console.info(`Backup success.`); 448 }).catch((err) => { 449 console.error(`Backup failed, err: ${err}`); 450 }) 451 ``` 452 453 (2) 调用数据库的恢复接口,从数据库的备份文件恢复数据库文件。 454 455 示例代码如下: 456 457 ```js 458 let promiseRestore = store.restore("dbBackup.db"); 459 promiseRestore.then(() => { 460 console.info(`Restore success.`); 461 }).catch((err) => { 462 console.error(`Restore failed, err: ${err}`); 463 }) 464 ``` 465 466## 相关实例 467针对关系型数据库开发,有以下相关实例可供参考: 468 469- [`DistributedRdb`:分布式关系型数据库(ArkTS)(API8)(Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-3.2-Release/data/DistributedRdb) 470 471- [关系型数据库(JS)(API8)](https://gitee.com/openharmony/codelabs/tree/master/Data/JSRelationshipData) 472 473- [关系型数据库(ArkS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Data/Rdb)