data-persistence-by-rdb-store.md 12.9 KB
Newer Older
A
Annie_wang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# Persisting RDB Store Data


## When to Use

A relational database (RDB) store is used to store data in complex relational models, such as the student information including names, student IDs, and scores of each subject, or employee information including names, employee IDs, and positions, based on SQLite. The data is more complex than key-value (KV) pairs due to strict mappings. You can use **RelationalStore** to implement persistence of this type of data.


## Basic Concepts

- **Predicates**: A representation of the property or feature of a data entity, or the relationship between data entities. It is used to define operation conditions.

- **ResultSet**: a set of query results, which allows access to the required data in flexible modes.


## Working Principles

**RelationalStore** provides APIs for applications to perform data operations. With SQLite as the underlying persistent storage engine, **RelationalStore** provides SQLite database features, including transactions, indexes, views, triggers, foreign keys, parameterized queries, prepared SQL statements, and more.

**Figure 1** Working mechanism
A
Annie_wang 已提交
21

A
Annie_wang 已提交
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
![relationStore_local](figures/relationStore_local.jpg)


## Constraints

- The default logging mode is Write Ahead Log (WAL), and the default flushing mode is **FULL** mode.

- An RDB store can be connected to a maximum of four connection pools for user read operations.

- To ensure data accuracy, only one write operation is allowed at a time.

- Once an application is uninstalled, related database files and temporary files on the device are automatically deleted.


## Available APIs

The following table lists the APIs used for RDB data persistence. Most of the APIs are executed asynchronously, using a callback or promise to return the result. The following table uses the callback-based APIs as an example. For more information about the APIs, see [RDB Store](../reference/apis/js-apis-data-relationalStore.md).

A
Annie_wang 已提交
40
| API| Description|
A
Annie_wang 已提交
41
| -------- | -------- |
A
Annie_wang 已提交
42 43 44 45 46 47 48
| getRdbStore(context: Context, config: StoreConfig, callback: AsyncCallback<RdbStore>): void | Obtains a **RdbStore** instance to implement RDB store operations. You can set **RdbStore** parameters based on actual requirements and use **RdbStore** APIs to perform data operations.|
| executeSql(sql: string, bindArgs: Array<ValueType>, callback: AsyncCallback<void>):void | Executes an SQL statement that contains specified arguments but returns no value.|
| insert(table: string, values: ValuesBucket, callback: AsyncCallback<number>):void | Inserts a row of data into a table.|
| update(values: ValuesBucket, predicates: RdbPredicates, callback: AsyncCallback<number>):void | Updates data in the RDB store based on the specified **RdbPredicates** instance.|
| delete(predicates: RdbPredicates, callback: AsyncCallback<number>):void | Deletes data from the RDB store based on the specified **RdbPredicates** instance.|
| query(predicates: RdbPredicates, columns: Array<string>, callback: AsyncCallback<ResultSet>):void | Queries data in the RDB store based on specified conditions.|
| deleteRdbStore(context: Context, name: string, callback: AsyncCallback<void>): void | Deletes an RDB store.|
A
Annie_wang 已提交
49 50 51 52 53 54 55


## How to Develop

1. Obtain an **RdbStore** instance.<br> Example:

   Stage model:
A
Annie_wang 已提交
56
   
A
Annie_wang 已提交
57 58 59
   ```js
   import relationalStore from '@ohos.data.relationalStore'; // Import the module.
   import UIAbility from '@ohos.app.ability.UIAbility';
A
Annie_wang 已提交
60

A
Annie_wang 已提交
61 62 63 64 65 66
   class EntryAbility extends UIAbility {
     onWindowStageCreate(windowStage) {
       const STORE_CONFIG = {
         name: 'RdbTest.db', // Database file name.
         securityLevel: relationalStore.SecurityLevel.S1 // Database security level.
       };
A
Annie_wang 已提交
67

A
Annie_wang 已提交
68
       // The RDB store version is 3, and the table structure is EMPLOYEE (NAME, AGE, SALARY, CODES).
A
Annie_wang 已提交
69
       const SQL_CREATE_TABLE ='CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER, SALARY REAL, CODES BLOB)'; // SQL statement for creating a data table.
A
Annie_wang 已提交
70

A
Annie_wang 已提交
71 72 73 74 75 76
       relationalStore.getRdbStore(this.context, STORE_CONFIG, (err, store) => {
         if (err) {
           console.error(`Failed to get RdbStore. Code:${err.code}, message:${err.message}`);
           return;
         }
         console.info(`Succeeded in getting RdbStore.`);
A
Annie_wang 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

        // When the RDB store is created, the default version is 0.
        if (store.version == 0) {
          store.executeSql(SQL_CREATE_TABLE); // Create a data table.
          // Set the RDB store version, which must be an integer greater than 0.
          store.version = 3;
        }

        // If the RDB store version is not 0 and does not match the current version, upgrade or downgrade the RDB store.
        // For example, upgrade the RDB store from version 1 to version 2.
        if (store.version != 3 && store.version == 1) {
          // Upgrade the RDB store from version 1 to version 2, and change the table structure from EMPLOYEE (NAME, SALARY, CODES, ADDRESS) to EMPLOYEE (NAME, AGE, SALARY, CODES, ADDRESS).
          store.executeSql("ALTER TABLE EMPLOYEE ADD COLUMN AGE INTEGER", null);
          store.version = 2;
        }

        // For example, upgrade the RDB store from version 2 to version 3.
        if (store.version != 3 && store.version == 2) {
          // Upgrade the RDB store from version 2 to version 3, and change the table structure from EMPLOYEE (NAME, AGE, SALARY, CODES, ADDRESS) to EMPLOYEE (NAME, AGE, SALARY, CODES).
          store.executeSql("ALTER TABLE EMPLOYEE DROP COLUMN ADDRESS TEXT", null);
          store.version = 3;
        }

A
Annie_wang 已提交
100
         // Perform operations such as adding, deleting, modifying, and querying data in the RDB store.
A
Annie_wang 已提交
101

A
Annie_wang 已提交
102 103 104 105 106 107 108
       });
     }
   }
   ```

   FA model:

A
Annie_wang 已提交
109
   
A
Annie_wang 已提交
110 111 112 113 114 115 116 117 118 119 120
   ```js
   import relationalStore from '@ohos.data.relationalStore'; // Import the module.
   import featureAbility from '@ohos.ability.featureAbility';
   
   // Obtain the context.
   let context = featureAbility.getContext();
   
   const STORE_CONFIG = {
     name: 'RdbTest.db', // Database file name.
     securityLevel: relationalStore.SecurityLevel.S1 // Database security level.
   };
A
Annie_wang 已提交
121 122

   // The RDB store version is 3, and the table structure is EMPLOYEE (NAME, AGE, SALARY, CODES).
A
Annie_wang 已提交
123
   const SQL_CREATE_TABLE ='CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER, SALARY REAL, CODES BLOB)'; // SQL statement for creating a data table.
A
Annie_wang 已提交
124

A
Annie_wang 已提交
125 126 127 128 129 130
   relationalStore.getRdbStore(context, STORE_CONFIG, (err, store) => {
     if (err) {
       console.error(`Failed to get RdbStore. Code:${err.code}, message:${err.message}`);
       return;
     }
     console.info(`Succeeded in getting RdbStore.`);
A
Annie_wang 已提交
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152

     // When the RDB store is created, the default version is 0.
     if (store.version == 0) {
        store.executeSql(SQL_CREATE_TABLE); // Create a data table.
        // Set the RDB store version, which must be an integer greater than 0.
        store.version = 3;
     }

     // If the RDB store version is not 0 and does not match the current version, upgrade or downgrade the RDB store.
     // For example, upgrade the RDB store from version 1 to version 2.
     if (store.version != 3 && store.version == 1) {
        // Upgrade the RDB store from version 1 to version 2, and change the table structure from EMPLOYEE (NAME, SALARY, CODES, ADDRESS) to EMPLOYEE (NAME, AGE, SALARY, CODES, ADDRESS).
        store.executeSql("ALTER TABLE EMPLOYEE ADD COLUMN AGE INTEGER", null);
        store.version = 2;
     }

     // For example, upgrade the RDB store from version 2 to version 3.
     if (store.version != 3 && store.version == 2) {
        // Upgrade the RDB store from version 2 to version 3, and change the table structure from EMPLOYEE (NAME, AGE, SALARY, CODES, ADDRESS) to EMPLOYEE (NAME, AGE, SALARY, CODES).
        store.executeSql("ALTER TABLE EMPLOYEE DROP COLUMN ADDRESS TEXT", null);
        store.version = 3;
     }
A
Annie_wang 已提交
153 154 155 156 157 158 159 160 161 162
   
     // Perform operations such as adding, deleting, modifying, and querying data in the RDB store.
   
   });
   ```

   > **NOTE**
   >
   > - The RDB store created by an application varies with the context. Multiple RDB stores are created for the same database name with different application contexts. For example, each UIAbility has its own context.
   > 
A
Annie_wang 已提交
163
   > - When an application calls **getRdbStore()** to obtain an RDB store instance for the first time, the corresponding database file is generated in the application sandbox. When the RDB store is used, temporary files ended with **-wal** and **-shm** may be generated in the same directory as the database file. If you want to move the database files to other places, you must also move these temporary files. After the application is uninstalled, the database files and temporary files generated on the device are also removed.
A
Annie_wang 已提交
164

A
Annie_wang 已提交
165 166 167 168
2. Use **insert()** to insert data to the RDB store. 
   
   Example:
   
A
Annie_wang 已提交
169 170 171 172 173 174 175 176 177 178 179 180 181
   ```js
   const valueBucket = {
     'NAME': 'Lisa',
     'AGE': 18,
     'SALARY': 100.5,
     'CODES': new Uint8Array([1, 2, 3, 4, 5])
   };
   store.insert('EMPLOYEE', valueBucket, (err, rowId) => {
     if (err) {
       console.error(`Failed to insert data. Code:${err.code}, message:${err.message}`);
       return;
     }
     console.info(`Succeeded in inserting data. rowId:${rowId}`);
A
Annie_wang 已提交
182
})
A
Annie_wang 已提交
183
   ```
A
Annie_wang 已提交
184
   
A
Annie_wang 已提交
185
   > **NOTE**
A
Annie_wang 已提交
186
>
A
Annie_wang 已提交
187
   > **RelationalStore** does not provide explicit flush operations for data persistence. Data inserted by **insert()** is stored in files persistently.
A
Annie_wang 已提交
188
   
A
Annie_wang 已提交
189 190
3. Modify or delete data based on the specified **Predicates** instance.

A
Annie_wang 已提交
191 192 193 194
   Use **update()** to modify data and **delete()** to delete data. 

   Example:

A
Annie_wang 已提交
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
   ```js
   // Modify data.
   const valueBucket = {
     'NAME': 'Rose',
     'AGE': 22,
     'SALARY': 200.5,
     'CODES': new Uint8Array([1, 2, 3, 4, 5])
   };
   let predicates = new relationalStore.RdbPredicates('EMPLOYEE'); // Create predicates for the table named EMPLOYEE.
   predicates.equalTo('NAME', 'Lisa'); // Modify the data of Lisa in the EMPLOYEE table to the specified data.
   store.update(valueBucket, predicates, (err, rows) => {
     if (err) {
       console.error(`Failed to update data. Code:${err.code}, message:${err.message}`);
       return;
     }
     console.info(`Succeeded in updating data. row count: ${rows}`);
   })
   
   // Delete data.
   let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
   predicates.equalTo('NAME', 'Lisa');
   store.delete(predicates, (err, rows) => {
     if (err) {
       console.error(`Failed to delete data. Code:${err.code}, message:${err.message}`);
       return;
     }
     console.info(`Delete rows: ${rows}`);
   })
   ```

4. Query data based on the conditions specified by **Predicates**.

A
Annie_wang 已提交
227 228 229 230
   Use **query()** to query data. The data obtained is returned in a **ResultSet** object. 

   Example:

A
Annie_wang 已提交
231 232 233
   ```js
   let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
   predicates.equalTo('NAME', 'Rose');
A
Annie_wang 已提交
234
   store.query(predicates, ['ID', 'NAME', 'AGE', 'SALARY'], (err, resultSet) => {
A
Annie_wang 已提交
235 236 237 238
     if (err) {
       console.error(`Failed to query data. Code:${err.code}, message:${err.message}`);
       return;
     }
A
Annie_wang 已提交
239 240 241 242 243 244 245 246 247 248 249
     console.info(`ResultSet column names: ${resultSet.columnNames}, column count: ${resultSet.columnCount}`);
     // resultSet is a cursor of a data set. By default, the cursor points to the -1st record. Valid data starts from 0.
     while (resultSet.goToNextRow()) {
       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"));
       console.info(`id=${id}, name=${name}, age=${age}, salary=${salary}`);
     }
     // Release the data set memory.
     resultSet.close();
A
Annie_wang 已提交
250 251 252 253 254 255 256 257 258
   })
   ```

   > **NOTE**
   >
   > Use **close()** to close the **ResultSet** that is no longer used in a timely manner so that the memory allocated can be released.

5. Delete the RDB store.

A
Annie_wang 已提交
259
   Use **deleteRdbStore()** to delete the RDB store and related database files.
A
Annie_wang 已提交
260

A
Annie_wang 已提交
261 262 263
   > **NOTE**
   >
   > After the deletion, you are advised to set the database object to null.
A
Annie_wang 已提交
264

A
Annie_wang 已提交
265
   Stage model:
A
Annie_wang 已提交
266

A
Annie_wang 已提交
267

A
Annie_wang 已提交
268 269 270 271 272 273 274 275 276 277
   ```js
   import UIAbility from '@ohos.app.ability.UIAbility';
   
   class EntryAbility extends UIAbility {
     onWindowStageCreate(windowStage) {
       relationalStore.deleteRdbStore(this.context, 'RdbTest.db', (err) => {
         if (err) {
           console.error(`Failed to delete RdbStore. Code:${err.code}, message:${err.message}`);
           return;
         }
A
Annie_wang 已提交
278
         store = null;
A
Annie_wang 已提交
279 280 281
         console.info('Succeeded in deleting RdbStore.');
       });
     }
A
Annie_wang 已提交
282
   }
A
Annie_wang 已提交
283 284 285
   ```

   FA model:
A
Annie_wang 已提交
286

A
Annie_wang 已提交
287

A
Annie_wang 已提交
288 289 290 291 292 293 294 295 296 297 298
   ```js
   import featureAbility from '@ohos.ability.featureAbility';
   
   // Obtain the context.
   let context = featureAbility.getContext();
   
   relationalStore.deleteRdbStore(context, 'RdbTest.db', (err) => {
     if (err) {
       console.error(`Failed to delete RdbStore. Code:${err.code}, message:${err.message}`);
       return;
     }
A
Annie_wang 已提交
299
     store = null;
A
Annie_wang 已提交
300 301 302
     console.info('Succeeded in deleting RdbStore.');
   });
   ```