database-relational-guidelines.md 13.7 KB
Newer Older
Z
zengyawen 已提交
1 2 3 4 5 6 7 8
# 关系型数据库开发指导

## 场景介绍

关系型数据库是在SQLite基础上实现的本地数据操作机制,提供给用户无需编写原生SQL语句就能进行数据增删改查的方法,同时也支持原生SQL语句操作。


## 接口说明
9
以下是关系型数据库的常用接口说明,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以Promise形式为例,更多接口及使用方式请见[关系型数据库](../reference/apis/js-apis-data-rdb.md)
Z
zengyawen 已提交
10

Z
zengyawen 已提交
11
### 数据库的创建和删除
Z
zengyawen 已提交
12 13 14 15 16

关系型数据库提供了数据库创建方式,以及对应的删除接口,涉及的API如下所示。

**表1** 数据库创建和删除API

S
sun-dou 已提交
17 18
| 接口名 | 描述 |
| -------- | -------- |
19 20
|getRdbStore(config:StoreConfig,version:number):Promise&lt;RdbStore&gt; | 获得一个相关的RdbStore,操作关系型数据库,用户可以根据自己的需求配置RdbStore的参数,然后通过RdbStore调用相关接口可以执行相关的数据操作,使用Promise异步回调。<br/>-config:与此RDB存储相关的数据库配置。<br/>-version:数据库版本。 |
| deleteRdbStore(name:string):Promise&lt;void&gt; | 使用指定的数据库文件配置删除数据库,使用Promise异步回调。<br/>-name:数据库名称。 |
Z
zengyawen 已提交
21

Z
zengyawen 已提交
22
### 数据库的增删改查
Z
zengyawen 已提交
23 24 25 26

关系型数据库提供对本地数据增删改查操作的能力,相关API如下所示。

- **新增**
Z
zengyawen 已提交
27 28 29
  
  关系型数据库提供了插入数据的接口,通过ValuesBucket输入要存储的数据,通过返回值判断是否插入成功,插入成功时返回最新插入数据所在的行号,失败时则返回-1。
  
Z
zengyawen 已提交
30 31 32
  **表2** 数据库插入API
  
  | 类名 | 接口名 | 描述 |
Z
zengyawen 已提交
33
  | -------- | -------- | -------- |
34
  | RdbStore | insert(name:string,values:ValuesBucket):Promise&lt;number&gt; | 向目标表中插入一行数据,使用Promise异步回调。<br>如果操作成功,返回行ID;否则返回-1。<br/>-name:指定的目标表名。<br/>-values:表示要插入到表中的数据行。 |
Z
zengyawen 已提交
35
  
Z
zengyawen 已提交
36
- **更新**
Z
zengyawen 已提交
37 38 39
  
  调用更新接口,传入要更新的数据,并通过RdbPredicates指定更新条件。该接口的返回值表示更新操作影响的行数。如果更新失败,则返回0。
  
Z
zengyawen 已提交
40 41 42
  **表3** 数据库更新API
  
  | 类名 | 接口名 | 描述 |
Z
zengyawen 已提交
43
  | -------- | -------- | -------- |
44
  | RdbStore | update(values:ValuesBucket,rdbPredicates:RdbPredicates):Promise\<number> | 根据RdbPredicates的指定实例对象更新数据库中的数据,使用Promise异步回调。<br>返回受影响的行数。<br/>-values:以ValuesBucket存储的要更新的数据。<br/>-rdbPredicates:表示RdbPredicates的实例对象指定的更新条件。 |
Z
zengyawen 已提交
45
  
Z
zengyawen 已提交
46 47
- **删除** 
  
Z
zengyawen 已提交
48 49
  调用删除接口,通过RdbPredicates指定删除条件。该接口的返回值表示删除的数据行数,可根据此值判断是否删除成功。如果删除失败,则返回0。
  
Z
zengyawen 已提交
50 51 52
  **表4** 数据库删除API
  
  | 类名 | 接口名 | 描述 |
Z
zengyawen 已提交
53
  | -------- | -------- | -------- |
54
  | RdbStore | delete(rdbPredicates:RdbPredicates):Promise\<number> | 根据rdbPredicates的指定实例对象从数据库中删除数据,使用Promise异步回调。<br>返回受影响的行数。<br/>-rdbPredicates:RdbPredicates的实例对象指定的删除条件。 |
Z
zengyawen 已提交
55
  
Z
zengyawen 已提交
56 57
- **查询** 

Z
zengyawen 已提交
58 59 60 61
  关系型数据库提供了两种查询数据的方式:

  - 直接调用查询接口。使用该接口,会将包含查询条件的谓词自动拼接成完整的SQL语句进行查询操作,无需用户传入原生的SQL语句。
  - 执行原生的SQL语句进行查询操作。
Z
zengyawen 已提交
62

Z
zengyawen 已提交
63
  **表5** 数据库查询API
Z
zengyawen 已提交
64

Z
zengyawen 已提交
65 66
  | 类名 | 接口名 | 描述 |
  | -------- | -------- | -------- |
67 68
  | RdbStore | query(rdbPredicates:RdbPredicates,columns:Array):Promise&lt;ResultSet&gt; | 根据指定条件查询数据库中的数据,使用Promise异步回调。<br/>-rdbPredicates:表示RdbPredicates的实例对象指定的查询条件。<br/>-columns:表示要查询的列。如果值为空,则查询应用于所有列。 |
  | RdbStore | querySql(sql:string,bindArgs?:Array&lt;ValueType&gt;):Promise&lt;ResultSet&gt; | 根据指定SQL语句查询数据库中的数据,使用Promise异步回调。<br/>-sql:指定要查询的SQL语句。<br/>-bindArgs:SQL语句中参数的值。 |
Z
zengyawen 已提交
69

Z
zengyawen 已提交
70
### 数据库谓词的使用
Z
zengyawen 已提交
71 72 73

关系型数据库提供了用于设置数据库操作条件的谓词RdbPredicates,该类确定RDB中条件表达式的值是true还是false。

74 75
以下列举几个常用谓词,更多谓词的使用请见[关系型数据库谓词](../reference/apis/js-apis-data-rdb.md#rdbpredicates)

Z
zengyawen 已提交
76 77 78 79
**表6** 数据库谓词API

| 类名 | 接口名 | 描述 |
| -------- | -------- | -------- |
80 81 82 83 84 85
| RdbPredicates | equalTo(field:string,value:ValueType):RdbPredicates | 配置谓词以匹配数据字段为ValueType且值等于指定值的字段。<br/>-field:数据库表中的列名。<br/>-value:指示要与谓词匹配的值。<br/>-RdbPredicates:返回与指定字段匹配的谓词。 |
| RdbPredicates | notEqualTo(field:string,value:ValueType):RdbPredicates | 配置谓词以匹配数据字段为ValueType且值不等于指定值的字段。<br/>-field:数据库表中的列名。<br/>-value:指示要与谓词匹配的值。<br/>-RdbPredicates:返回与指定字段匹配的谓词。 |
| RdbPredicates | or():RdbPredicates | 将或条件添加到谓词中。<br/>-RdbPredicates:返回带有或条件的谓词。 |
| RdbPredicates | and():RdbPredicates | 向谓词添加和条件。<br/>-RdbPredicates:返回带有和条件的谓词。 |
| RdbPredicates | contains(field:string,value:string):RdbPredicats | 配置谓词以匹配数据字段为String且value包含指定值的字段。<br/>-field:数据库表中的列名。<br/>-value:指示要与谓词匹配的值。<br/>-RdbPredicates:返回带有包含条件的谓词。 |

Z
zengyawen 已提交
86

Z
zengyawen 已提交
87
### 查询结果集的使用
Z
zengyawen 已提交
88

89 90 91
关系型数据库提供了查询返回的结果集ResultSet,其指向查询结果中的一行数据,供用户对查询结果进行遍历和访问。

更多结果集的接口使用,请见[结果集](../reference/apis/js-apis-data-resultset.md)
Z
zengyawen 已提交
92

93
> **须知:**
Z
zengyawen 已提交
94
> **结果集使用完后,请一定要调用close方法显式关闭。**
Z
zengyawen 已提交
95 96 97 98 99

**表7** 结果集API

| 类名 | 接口名 | 描述 |
| -------- | -------- | -------- |
100 101 102 103 104 105
| ResultSet | goToFirstRow():boolean | 将结果集移动到第一行。 |
| ResultSet | getString(columnIndex:number):string | 获取当前行指定列的值,以String类型返回。 |
| ResultSet | getBlob(columnIndex:number):Uint8Array | 获取当前行指定列的值,以字节数组形式返回。 |
| ResultSet | getDouble(columnIndex:number):number | 获取当前行指定列的值,以double型返回。 |
| ResultSet | getLong(columnIndex:number):number     | 获取当前行指定列的值,以Long形式返回。     |
| ResultSet | close():void | 关闭结果集。 |
Z
zengyawen 已提交
106 107 108



Z
zengyawen 已提交
109
### 设置分布式列表
S
sun-dou 已提交
110

Z
zengyawen 已提交
111
**设置分布式列表**
S
sun-dou 已提交
112

Z
zengyawen 已提交
113
**表8** 设置分布式列表
S
sun-dou 已提交
114 115 116

| 类名 | 接口名 | 描述 |
| -------- | -------- | -------- |
117
| RdbStore | setDistributedTables(tables: Array\<string>): Promise\<void>; | 设置分布式列表,使用Promise异步回调。<br/>-tables:要设置的分布式列表表名。 |
S
sun-dou 已提交
118

Z
zengyawen 已提交
119
**根据本地表名获取指定远程设备的分布式表名**
S
sun-dou 已提交
120 121 122

用户根据本地表名获取指定远程设备的分布式表名。在查询远程设备数据库时,需要使用分布式表名。

Z
zengyawen 已提交
123
**表9** 根据本地表名获取指定远程设备的分布式表名
S
sun-dou 已提交
124 125 126

| 类名 | 接口名 | 描述 |
| -------- | -------- | -------- |
127
| RdbStore | obtainDistributedTableName(device: string, table: string): Promise\<string>; | 根据本地表名获取指定远程设备的分布式表名。在查询远程设备数据库时,需要使用分布式表名,使用Promise异步回调。<br/>-device:远程设备。<br/>-table:本地表名。 |
S
sun-dou 已提交
128

Z
zengyawen 已提交
129
**在设备之间同步数据**
S
sun-dou 已提交
130

Z
zengyawen 已提交
131
**表10** 在设备之间同步数据
S
sun-dou 已提交
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表示成功,其他值表示失败。  |
S
sun-dou 已提交
136

Z
zengyawen 已提交
137
**注册数据库的观察者**
S
sun-dou 已提交
138

Z
zengyawen 已提交
139
**表11** 注册数据库的观察者
S
sun-dou 已提交
140 141 142

| 类名 | 接口名 | 描述 |
| -------- | -------- | -------- |
143
| RdbStore |on(event: 'dataChange', type: SubscribeType, observer: Callback<Array\<string>>): void;| 注册数据库的观察者。当分布式数据库中的数据发生更改时,将调用回调。<br/>-type:指在{@code SubscribeType}中定义的订阅类型;SUBSCRIBE_TYPE_REMOTE 订阅远程数据更改。<br/>-observer:指分布式数据库中数据更改事件的观察者。 |
S
sun-dou 已提交
144

Z
zengyawen 已提交
145
**从数据库中删除指定类型的指定观察者**
S
sun-dou 已提交
146

Z
zengyawen 已提交
147
**表12** 从数据库中删除指定类型的指定观察者
S
sun-dou 已提交
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:指已注册的数据更改观察者。 |
S
sun-dou 已提交
152

Z
zengyawen 已提交
153 154 155 156 157 158 159 160 161 162

## 开发步骤

1. 创建数据库。
   1. 配置数据库相关信息,包括数据库的名称、存储模式、是否为只读模式等。
   2. 初始化数据库表结构和相关数据。
   3. 创建数据库。

   示例代码如下:

163
   ```js
164
   import data_rdb from '@ohos.data.rdb'
Z
zengyawen 已提交
165 166 167
   
   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)";
   const STORE_CONFIG = {name: "rdbstore.db",}
W
wuyongning 已提交
168
   data_rdb.getRdbStore(STORE_CONFIG, 1, function (err, rdbStore) {
169
       rdbStore.executeSql(CREATE_TABLE_TEST )
W
wuyongning 已提交
170 171
       console.info('create table done.')
   })
Z
zengyawen 已提交
172 173 174 175 176 177 178 179
   ```

2. 插入数据。
   1. 构造要插入的数据,以ValuesBucket形式存储。
   2. 调用关系型数据库提供的插入接口。

   示例代码如下:

180
   ```js
Z
zengyawen 已提交
181 182 183 184 185 186 187 188 189 190 191 192
   var u8 = new Uint8Array([1, 2, 3])
   const valueBucket = {"name": "Tom", "age": 18, "salary": 100.5, "blobType": u8,}
   let insertPromise = rdbStore.insert("test", valueBucket)
   ```

3. 查询数据。
   1. 构造用于查询的谓词对象,设置查询条件。
   2. 调用查询接口查询数据。
   3. 调用结果集接口,返回查询结果。

   示例代码如下:

193
   ```js
194
   let predicates = new data_rdb.RdbPredicates("test");
Z
zengyawen 已提交
195
   predicates.equalTo("name", "Tom")
W
wuyongning 已提交
196 197 198 199 200 201 202 203 204 205
   let promisequery = rdbStore.query(predicates)
       promisequery.then((resultSet) => {
       resultSet.goToFirstRow()
       const id = resultSet.getLong(resultSet.getColumnIndex("id"))
       const name = resultSet.getString(resultSet.getColumnIndex("name"))
       const age = resultSet.getLong(resultSet.getColumnIndex("age"))
       const salary = resultSet.getDouble(resultSet.getColumnIndex("salary"))
       const blobType = resultSet.getBlob(resultSet.getColumnIndex("blobType"))
       resultSet.close()
   })
Z
zengyawen 已提交
206
   ```
S
sun-dou 已提交
207 208 209 210 211 212 213

4. 设置分布式同步表。
   1. 数据库调用接口设置分布式同步列表。
   2. 判断是否设置成功。

   示例代码如下:

214
   ```js
S
sun-dou 已提交
215 216 217 218
   let promise = rdbStore.setDistributedTables(["test"])
   promise.then(() => {
       console.info("setDistributedTables success.")
   }).catch((err) => {
219
       console.info("setDistributedTables failed.")
S
sun-dou 已提交
220 221 222 223 224 225 226 227 228 229
   })
   ```

 5. 分布式数据同步。
    1. 构造用于同步分布式表的谓词对象,指定组网内的远程设备。
    2. 调用同步数据的接口 。
    3. 判断是否数据同步成功。

    示例代码如下:

230
    ```js
231
    let predicate = new data_rdb.RdbPredicates('test')
S
sun-dou 已提交
232 233
    predicate.inDevices(['12345678abcde'])
    let promise = rdbStore.sync(rdb.SyncMode.SYNC_MODE_PUSH, predicate)
234
    promise.then((result) => {
S
sun-dou 已提交
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
        console.log('sync done.')
        for (let i = 0; i < result.length; i++) {
            console.log('device=' + result[i][0] + ' status=' + result[i][1])
        }
    }).catch((err) => {
        console.log('sync failed')
    })
    ```

6. 分布式数据订阅。
    1. 调用分布式数据订阅接口,注册数据库的观察者。
    2. 当分布式数据库中的数据发生更改时,将调用回调。

    示例代码如下:

250
    ```js
S
sun-dou 已提交
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
    function storeObserver(devices) {
        for (let i = 0; i < devices.length; i++) {
            console.log('device=' + device[i] + ' data changed')
        }
    }
    try {
        rdbStore.on('dataChange', rdb.SubscribeType.SUBSCRIBE_TYPE_REMOTE, storeObserver)
    } catch (err) {
        console.log('register observer failed')
    }
    ```

7. 跨设备查询。
    1. 根据本地表名获取指定远程设备的分布式表名。
    2. 调用结果集接口,返回查询结果。

    示例代码如下:

269
    ```js
S
sun-dou 已提交
270 271
    let tableName = rdbStore.obtainDistributedTableName(deviceId, "test");
    let resultSet = rdbStore.querySql("SELECT * FROM " + tableName)
S
sun-dou 已提交
272
    ```
273 274
## 相关实例
针对关系型数据库开发,有以下相关实例可供参考:
275
- [`Rdb`:关系型数据库(eTS)(API8)](https://gitee.com/openharmony/app_samples/tree/master/data/Rdb)
G
ge-yafang 已提交
276
- [`DistributedRdb`:分布式关系型数据库(eTS)(API8)](https://gitee.com/openharmony/app_samples/tree/master/data/DistributedRdb)
277
- [关系型数据库(JS)(API8)](https://gitee.com/openharmony/codelabs/tree/master/Data/JSRelationshipData)