1# Cross-Device Sync of RDB Stores 2 3 4## When to Use 5 6You can sync the application data in a local RDB store on a device to other devices that form a Super Device. 7 8 9## Basic Concepts 10 11OpenHamony supports sync of the relational data of an application across multiple devices. 12 13- If a table created for an application in the database is set as a distributed table, when data is queried from the RDB store of a remote device, the distributed table name of the remote device can be obtained based on the local table name. 14 15- Data can be synced between devices in either of the following ways: <br>- Pushing data from a local device to a remote device. <br>- Pulling data from a remote device to a local device. 16 17 18## Working Principles 19 20After completing device discovery and authentication, the underlying communication component notifies the application that the device goes online. The **DatamgrService** then establishes an encrypted transmission channel to synchronize data between the two devices. 21 22 23### Cross-Device Data Sync Mechanism 24 25 26 27After writing data to an RDB store, the service sends a sync request to the **DatamgrService**. 28 29The **DatamgrService** reads the data to be synced from the application sandbox and sends the data to the **DatamgrService** of the target device based on the **deviceId** of the peer device. Then, the **DatamgrService** writes the data to the RDB of the same application. 30 31 32### Data Change Notification Mechanism 33 34When data is added, deleted, or modified, a notification is sent to the subscriber. The notifications can be classified into the following types: 35 36- Local data change notification: subscription of the application data changes on the local device. When the data in the local KV store is added, deleted, or modified in the database, a notification is received. 37 38- Distributed data change notification: subscription of the application data changes of other devices in the network. When the data in the local RDB store changes after being synced with data from another device in the same network, a notification is received. 39 40 41## Constraints 42 43- A maximum of 16 RDB stores can be opened simultaneously for an application. 44 45- Each RDB store supports a maximum of eight callbacks for subscription of data change notifications. 46 47- A table containing composite keys cannot be set as a distributed table. 48 49## Available APIs 50 51Most of the APIs for cross-device data sync of RDB stores 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-arkdata/js-apis-data-relationalStore.md). 52 53| API| Description| 54| -------- | -------- | 55| setDistributedTables(tables: Array<string>, callback: AsyncCallback<void>): void | Sets the distributed tables to be synced.| 56| sync(mode: SyncMode, predicates: RdbPredicates, callback: AsyncCallback<Array<[string, number]>>): void | Synchronizes data across devices.| 57| on(event: 'dataChange', type: SubscribeType, observer: Callback<Array<string>>): void | Subscribes to changes in the distributed data.| 58| off(event:'dataChange', type: SubscribeType, observer: Callback<Array<string>>): void | Unsubscribe from changes in the distributed data.| 59| obtainDistributedTableName(device: string, table: string, callback: AsyncCallback<string>): void | Obtains the table name on the specified device based on the local table name.| 60| remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array<string> , callback: AsyncCallback<ResultSet>): void | Queries data from the RDB store of a remote device based on specified conditions.| 61 62 63## How to Develop 64 65> **NOTE** 66> 67> The security level of the destination device (to which data is synced) cannot be higher than that of the source device. For details, see [Access Control Mechanism in Cross-Device Sync](access-control-by-device-and-data-level.md#access-control-mechanism-in-cross-device-sync). 68 691. Import the module. 70 71 ```ts 72 import { relationalStore } from '@kit.ArkData'; 73 ``` 74 752. Request permissions. 76 77 1. Declare the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md). 78 2. Display a dialog box to ask for user authorization when the application is started for the first time. For details, see [Requesting User Authorization](../security/AccessToken/request-user-authorization.md). 79 803. Create an RDB store and set a table for distributed sync. 81 82 ```ts 83 import { UIAbility } from '@kit.AbilityKit'; 84 import { BusinessError } from '@kit.BasicServicesKit'; 85 import { window } from '@kit.ArkUI'; 86 87 class EntryAbility extends UIAbility { 88 onWindowStageCreate(windowStage: window.WindowStage) { 89 const STORE_CONFIG: relationalStore.StoreConfig = { 90 name: "RdbTest.db", 91 securityLevel: relationalStore.SecurityLevel.S3 92 }; 93 94 relationalStore.getRdbStore(this.context, STORE_CONFIG, (err: BusinessError, store: relationalStore.RdbStore) => { 95 store.executeSql('CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER, SALARY REAL, CODES BLOB)', (err) => { 96 // Set the table for distributed sync. 97 store.setDistributedTables(['EMPLOYEE']); 98 // Perform related operations. 99 }) 100 }) 101 } 102 } 103 ``` 104 1054. Synchronize data across devices. After **sync()** is called to trigger a sync, data is synced from the local device to all other devices on the network. 106 107 ```ts 108 // Construct the predicate object for synchronizing the distributed table. 109 let predicates = new relationalStore.RdbPredicates('EMPLOYEE'); 110 // Call sync() to synchronize data. 111 if(store != undefined) 112 { 113 (store as relationalStore.RdbStore).sync(relationalStore.SyncMode.SYNC_MODE_PUSH, predicates, (err, result) => { 114 // Check whether data sync is successful. 115 if (err) { 116 console.error(`Failed to sync data. Code:${err.code},message:${err.message}`); 117 return; 118 } 119 console.info('Succeeded in syncing data.'); 120 for (let i = 0; i < result.length; i++) { 121 console.info(`device:${result[i][0]},status:${result[i][1]}`); 122 } 123 }) 124 } 125 ``` 126 1275. Subscribe to changes in the distributed data. The data sync triggers the **observer** callback registered in **on()**. The input parameter of the callback is the ID of the device whose data changes. 128 129 ```ts 130 let devices: string | undefined = undefined; 131 try { 132 // Register an observer to listen for the changes of the distributed data. 133 // When data in the RDB store changes, the registered callback will be invoked to return the data changes. 134 if(store != undefined) { 135 (store as relationalStore.RdbStore).on('dataChange', relationalStore.SubscribeType.SUBSCRIBE_TYPE_REMOTE, (storeObserver)=>{ 136 if(devices != undefined){ 137 for (let i = 0; i < devices.length; i++) { 138 console.info(`The data of device:${devices[i]} has been changed.`); 139 } 140 } 141 }); 142 } 143 } catch (err) { 144 console.error('Failed to register observer. Code:${err.code},message:${err.message}'); 145 } 146 // You can unsubscribe from the data changes if required. 147 try { 148 if(store != undefined) { 149 (store as relationalStore.RdbStore).off('dataChange', relationalStore.SubscribeType.SUBSCRIBE_TYPE_REMOTE, (storeObserver)=>{ 150 }); 151 } 152 } catch (err) { 153 console.error('Failed to register observer. Code:${err.code},message:${err.message}'); 154 } 155 ``` 156 1576. Query data across devices. If data sync is not complete or triggered, an application can call **remoteQuery()** to query data from a remote device. 158 159 > **NOTE** 160 > 161 > The value of **deviceIds** can be obtained by using [deviceManager.getAvailableDeviceListSync](../reference/apis-distributedservice-kit/js-apis-distributedDeviceManager.md#getavailabledevicelistsync) method. 162 163 164 ```ts 165 // Obtain device IDs. 166 import { distributedDeviceManager } from '@kit.DistributedServiceKit'; 167 import { BusinessError } from '@kit.BasicServicesKit'; 168 169 let dmInstance: distributedDeviceManager.DeviceManager; 170 let deviceId: string | undefined = undefined ; 171 172 try { 173 dmInstance = distributedDeviceManager.createDeviceManager("com.example.appdatamgrverify"); 174 let devices = dmInstance.getAvailableDeviceListSync(); 175 176 deviceId = devices[0].networkId; 177 178 // Construct a predicate object for querying the distributed table. 179 let predicates = new relationalStore.RdbPredicates('EMPLOYEE'); 180 // Query data from the specified remote device and return the query result. 181 if(store != undefined && deviceId != undefined) { 182 (store as relationalStore.RdbStore).remoteQuery(deviceId, 'EMPLOYEE', predicates, ['ID', 'NAME', 'AGE', 'SALARY', 'CODES'], 183 (err: BusinessError, resultSet: relationalStore.ResultSet) => { 184 if (err) { 185 console.error(`Failed to remoteQuery data. Code:${err.code},message:${err.message}`); 186 return; 187 } 188 console.info(`ResultSet column names: ${resultSet.columnNames}, column count: ${resultSet.columnCount}`); 189 } 190 ) 191 } 192 } catch (err) { 193 let code = (err as BusinessError).code; 194 let message = (err as BusinessError).message; 195 console.error("createDeviceManager errCode:" + code + ",errMessage:" + message); 196 } 197 ``` 198 199