1# Database Backup and Restore (ArkTS) 2 3## When to Use 4 5You may need to restore a database in any of the following cases: 6 7An important operation being performed by an application is interrupted. 8 9The database is unavailable due to data loss or corruption, or dirty data. 10 11 12Both KV stores and RDB stores support database backup and restore. You can also delete KV store backups to release local storage space. 13 14 15## Backing Up, Restoring, and Deleting a KV Store 16 17You can use **backup()** to back up a KV store, use **restore()** to restore a KV store, and use **deletebackup()** to delete a KV store backup file. For details about the APIs, see [Distributed KV Store](../reference/apis-arkdata/js-apis-distributedKVStore.md). 18 191. Create a KV store. 20 21 (1) Create a **kvManager** instance. 22 23 (2) Set database parameters. 24 25 (3) Create a **kvStore** instance. 26 27 28 ```ts 29 import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; 30 import { hilog } from '@kit.PerformanceAnalysisKit'; 31 import { distributedKVStore } from '@kit.ArkData'; 32 import { BusinessError } from '@kit.BasicServicesKit'; 33 34 export default class EntryAbility extends UIAbility { 35 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 36 this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); 37 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); 38 let kvManager: distributedKVStore.KVManager; 39 let kvStore: distributedKVStore.SingleKVStore | undefined = undefined; 40 let context = this.context; 41 const kvManagerConfig: distributedKVStore.KVManagerConfig = { 42 context: context, 43 bundleName: 'com.example.datamanagertest' 44 } 45 try { 46 kvManager = distributedKVStore.createKVManager(kvManagerConfig); 47 console.info('Succeeded in creating KVManager.'); 48 try { 49 const options: distributedKVStore.Options = { 50 createIfMissing: true, 51 encrypt: true, 52 backup: false, 53 autoSync: false, 54 kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, 55 securityLevel: distributedKVStore.SecurityLevel.S3 56 }; 57 kvManager.getKVStore<distributedKVStore.SingleKVStore>('storeId', options, (err, store: distributedKVStore.SingleKVStore) => { 58 if (err) { 59 console.error(`Failed to get KVStore. Code:${err.code},message:${err.message}`); 60 return; 61 } 62 console.info('Succeeded in getting KVStore.'); 63 kvStore = store; 64 }); 65 } catch (e) { 66 let error = e as BusinessError; 67 console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`); 68 } 69 } catch (e) { 70 let error = e as BusinessError; 71 console.error(`Failed to create KVManager. Code:${error.code},message:${error.message}`); 72 } 73 74 if (kvStore !== undefined) { 75 kvStore = kvStore as distributedKVStore.SingleKVStore; 76 // Perform subsequent operations. 77 //... 78 } 79 } 80 } 81 ``` 82 832. Call **put()** to insert data to the KV store. 84 85 ```ts 86 const KEY_TEST_STRING_ELEMENT = 'key_test_string'; 87 const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; 88 try { 89 kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => { 90 if (err !== undefined) { 91 console.error(`Fail to put data. Code:${err.code},message:${err.message}`); 92 return; 93 } 94 console.info('Succeeded in putting data.'); 95 }); 96 } catch (e) { 97 let error = e as BusinessError; 98 console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`); 99 } 100 ``` 101 1023. Call **backup()** to back up the KV store. 103 104 ```ts 105 let backupFile = 'BK001'; 106 try { 107 kvStore.backup(backupFile, (err) => { 108 if (err) { 109 console.error(`Fail to backup data.code:${err.code},message:${err.message}`); 110 } else { 111 console.info('Succeeded in backuping data.'); 112 } 113 }); 114 } catch (e) { 115 let error = e as BusinessError; 116 console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`); 117 } 118 ``` 119 1204. Call **delete()** to delete data to simulate unexpected deletion or data tampering. 121 122 ```ts 123 try { 124 kvStore.delete(KEY_TEST_STRING_ELEMENT, (err) => { 125 if (err !== undefined) { 126 console.error(`Fail to delete data. Code:${err.code},message:${err.message}`); 127 return; 128 } 129 console.info('Succeeded in deleting data.'); 130 }); 131 } catch (e) { 132 let error = e as BusinessError; 133 console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`); 134 } 135 ``` 136 1375. Call **restore()** to restore the KV store. 138 139 ```ts 140 try { 141 kvStore.restore(backupFile, (err) => { 142 if (err) { 143 console.error(`Fail to restore data. Code:${err.code},message:${err.message}`); 144 } else { 145 console.info('Succeeded in restoring data.'); 146 } 147 }); 148 } catch (e) { 149 let error = e as BusinessError; 150 console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`); 151 } 152 ``` 153 1546. Call **deleteBackup()** to delete the backup file to release storage space. 155 156 ```ts 157 let files = [backupFile]; 158 try { 159 kvStore.deleteBackup(files).then((data) => { 160 console.info(`Succeed in deleting Backup. Data:filename is ${data[0]},result is ${data[1]}.`); 161 }).catch((err: BusinessError) => { 162 console.error(`Fail to delete Backup. Code:${err.code},message:${err.message}`); 163 }) 164 } catch (e) { 165 let error = e as BusinessError; 166 console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`); 167 } 168 ``` 169 170## Backing Up an RDB Store 171 172A database backup can be used to quickly restore an RDB store in abnormal state. 173 174Two backup modes are available: manual backup and automatic backup. Automatic backup is available only for system applications. 175 176### Manual Backup 177 178Call the [backup](../reference/apis-arkdata/arkts-apis-data-relationalStore-RdbStore.md#backup) API to manually back up an RDB store. <br>Example: 179 180```ts 181import { UIAbility } from '@kit.AbilityKit'; 182import { relationalStore } from '@kit.ArkData'; 183import { BusinessError } from '@kit.BasicServicesKit'; 184 185export default class EntryAbility extends UIAbility { 186 async onCreate(): Promise<void> { 187 let store: relationalStore.RdbStore | undefined = undefined; 188 let context = this.context; 189 190 const STORE_CONFIG: relationalStore.StoreConfig = { 191 name: 'RdbTest.db', 192 securityLevel: relationalStore.SecurityLevel.S3, 193 allowRebuild: true 194 }; 195 try { 196 store = await relationalStore.getRdbStore(context, STORE_CONFIG); 197 await store.executeSql('CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER, SALARY REAL, CODES BLOB)'); 198 console.info('Succeeded in getting RdbStore.'); 199 } catch (e) { 200 const err = e as BusinessError; 201 console.error(`Failed to get RdbStore. Code:${err.code},message:${err.message}`); 202 } 203 204 if (!store) { 205 return; 206 } 207 208 try { 209 /** 210 * Backup.db specifies the database backup file. By default, it is in the same directory as the RDB store. 211 * You can also specify an absolute path, for example, /data/storage/el2/database/Backup.db. The file path must exist and will not be automatically created. 212 */ 213 await store.backup("Backup.db"); 214 console.info(`Succeeded in backing up RdbStore.`); 215 } catch (e) { 216 const err = e as BusinessError; 217 console.error(`Failed to backup RdbStore. Code:${err.code}, message:${err.message}`); 218 } 219 } 220} 221``` 222 223<!--Del--> 224 225### Automatic Backup (for System Applications Only) 226 227To implement hot backup of an RDB store, set **haMode** in [StoreConfig](../reference/apis-arkdata/js-apis-data-relationalStore-sys.md#storeconfig) to **MAIN_REPLICA**. This parameter is available only for system applications. <br>Example: 228 229```ts 230import { UIAbility } from '@kit.AbilityKit'; 231import { relationalStore } from '@kit.ArkData'; 232import { BusinessError } from '@kit.BasicServicesKit'; 233 234export default class EntryAbility extends UIAbility { 235 async onCreate(): Promise<void> { 236 let store: relationalStore.RdbStore | undefined = undefined; 237 let context = this.context; 238 try { 239 // Set haMode of StoreConfig to MAIN_REPLICA. 240 const AUTO_BACKUP_CONFIG: relationalStore.StoreConfig = { 241 name: "BackupRestoreTest.db", 242 securityLevel: relationalStore.SecurityLevel.S3, 243 haMode: relationalStore.HAMode.MAIN_REPLICA, // Data is written to the main and replica stores on a real-time basis. 244 allowRebuild: true 245 } 246 247 // Call getRdbStore() to create an RDB store instance. 248 store = await relationalStore.getRdbStore(context, AUTO_BACKUP_CONFIG); 249 console.info('Succeeded in getting RdbStore.'); 250 } catch (e) { 251 const err = e as BusinessError; 252 console.error(`Failed to get RdbStore. Code:${err.code}, message:${err.message}`); 253 } 254 } 255} 256``` 257 258<!--DelEnd--> 259 260## Rebuilding an RDB Store 261 262If error 14800011 is displayed when an RDB store is created or used, an exception occurs in the database. You can delete the database and restore data. 263 264You can set **allowRebuild** in [StoreConfig](../reference/apis-arkdata/arkts-apis-data-relationalStore-i.md#storeconfig) to **true**, which allows the database to be automatically deleted when an exception occurs. The newly rebuilt RDB store is empty. You need to create tables and restore data from the database backup. For details about how to back up RDB store data, see [Backing Up an RDB Store](#backing-up-an-rdb-store). For details about how to restore RDB store data, see [Restoring RDB Store Data](#restoring-rdb-store-data). 265 266If **allowRebuild** in **StoreConfig** is set to **true** before the database is abnormal, the database will be automatically deleted when an exception occurs. 267 268If **allowRebuild** in **StoreConfig** is not set or is set to **false**, set **allowRebuild** to **true** and open the rebuilt RDB store. <br>Example: 269 270```ts 271import { UIAbility } from '@kit.AbilityKit'; 272import { relationalStore } from '@kit.ArkData'; 273import { BusinessError } from '@kit.BasicServicesKit'; 274 275export default class EntryAbility extends UIAbility { 276 async onCreate(): Promise<void> { 277 let store: relationalStore.RdbStore | undefined = undefined; 278 let context = this.context; 279 try { 280 const STORE_CONFIG: relationalStore.StoreConfig = { 281 name: 'RdbTest.db', 282 securityLevel: relationalStore.SecurityLevel.S3, 283 allowRebuild: true 284 }; 285 store = await relationalStore.getRdbStore(context, STORE_CONFIG); 286 await store.executeSql('CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER, SALARY REAL, CODES BLOB)'); 287 console.info('Succeeded in getting RdbStore.'); 288 } catch (e) { 289 const err = e as BusinessError; 290 console.error(`Failed to get RdbStore. Code:${err.code}, message:${err.message}`); 291 } 292 } 293} 294``` 295 296## Restoring RDB Store Data 297 298If an RDB store is abnormal, you can restore it by using the database backup. 299 300You can restore data from either the manual backup data or automatic backup data. The latter is available only for system applications. 301 302### Restoring from Manual Backup Data 303 304You can use **backup()** to [perform manual backup](#manual-backup) and use **restore()** to restore data from the manual backup data. 305 306The following example contains only the code snippet for the restore process. The complete code must also contain the code for backing up data and rebuilding an RDB store. 307 3081. Throws an error code to indicate a database exception. 309 310 ```ts 311 let predicates = new relationalStore.RdbPredicates("EMPLOYEE"); 312 if (store != undefined) { 313 (store as relationalStore.RdbStore).query(predicates, ["ID", "NAME", "AGE", "SALARY", "CODES"]).then((result: relationalStore.ResultSet) => { 314 let resultSet = result; 315 try { 316 /* ... 317 Logic for adding, deleting, and modifying data. 318 ... 319 */ 320 // Throw an exception. 321 if (resultSet?.rowCount == -1) { 322 resultSet ?.isColumnNull(0); 323 } 324 // Call other APIs such as resultSet.goToFirstRow() and resultSet.count(), which also throw exceptions. 325 while (resultSet.goToNextRow()) { 326 console.info(JSON.stringify(resultSet.getRow())) 327 } 328 resultSet.close(); 329 } catch (err) { 330 if (err.code === 14800011) { 331 // Perform step 2 (close result sets and then restore data). 332 } 333 console.error(JSON.stringify(err)); 334 } 335 }) 336 } 337 ``` 338 3392. Close all opened result sets. 340 341 ```ts 342 // Obtain all opened result sets. 343 let resultSets: Array<relationalStore.ResultSet> = []; 344 // Call resultSet.close() to close all opened result sets. 345 for (let resultSet of resultSets) { 346 try { 347 resultSet.close(); 348 } catch (e) { 349 if (e.code !== 14800014) { 350 console.error(`Code:${e.code}, message:${e.message}`); 351 } 352 } 353 } 354 ``` 355 3563. Call **restore()** to restore data. 357 358 ```ts 359 import { UIAbility } from '@kit.AbilityKit'; 360 import { relationalStore } from '@kit.ArkData'; 361 import { BusinessError } from '@kit.BasicServicesKit'; 362 import { fileIo } from '@kit.CoreFileKit'; 363 364 export default class EntryAbility extends UIAbility { 365 async onCreate(): Promise<void> { 366 let store: relationalStore.RdbStore | undefined = undefined; 367 let context = this.context; 368 let STORE_CONFIG: relationalStore.StoreConfig = { 369 name: "RdbTest.db", 370 securityLevel: relationalStore.SecurityLevel.S3, 371 allowRebuild: true 372 } 373 try { 374 /** 375 * Backup.db specifies the database backup file. By default, it is in the same directory as the current database. 376 * If an absolute path is specified for the database backup file, for example, /data/storage/el2/database/Backup.db, pass in the absolute path. 377 */ 378 let backupFilePath = context.databaseDir + '/rdb/Backup.db'; 379 const backupExist = await fileIo.access(backupFilePath); 380 if (!backupExist) { 381 console.info("Backup is not exist."); 382 // Open the rebuilt RDB store and create tables. 383 // Generate data. 384 return; 385 } 386 } catch (e) { 387 console.error(`Code:${e.code}, message:${e.message}`); 388 } 389 390 try { 391 store = await relationalStore.getRdbStore(context, STORE_CONFIG); 392 // Call restore() to restore data. 393 await store.restore("Backup.db"); 394 console.log("Restore from back success.") 395 } catch (e) { 396 const err = e as BusinessError; 397 console.error(`Failed to get RdbStore. Code:${err.code}, message:${err.message}`); 398 } 399 } 400 } 401 ``` 402 403<!--Del--> 404 405### Restoring from Automatic Backup Data (for System Applications Only) 406 407Call [restore()](../reference/apis-arkdata/js-apis-data-relationalStore-sys.md#restore12) to restore data from the [automatic backup data](#automatic-backup-for-system-applications-only). Only system applications support this operation. 408 409The following example contains only the code snippet for the restore process. The complete code must also contain the code for backing up data and rebuilding an RDB store. 410 411 ```ts 412 if (store !== undefined) { 413 try { 414 // Add, delete, modify, and query data. 415 } catch (err) { 416 if (err.code == 14800011) { 417 // Obtain all opened result sets. 418 let resultSets: Array<relationalStore.ResultSet> = []; 419 // Call resultSet.close() to close all opened result sets. 420 for (let resultSet of resultSets) { 421 try { 422 resultSet.close(); 423 } catch (e) { 424 if (e.code !== 14800014) { 425 console.error(`Code:${e.code}, message:${e.message}`); 426 } 427 } 428 } 429 430 (store as relationalStore.RdbStore).restore("Backup.db", (err: BusinessError) => { 431 if (err) { 432 console.error(`Failed to restore RdbStore. Code:${err.code}, message:${err.message}`); 433 return; 434 } 435 console.info(`Succeeded in restoring RdbStore.`); 436 }) 437 } 438 console.error(`Code:${err.code}, message:${err.message}`); 439 } 440 } 441 ``` 442 443<!--DelEnd--> 444 445<!--RP1--><!--RP1End--> 446