• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Cross-Device Synchronization of RDB Stores
2
3
4## When to Use
5
6You can synchronize the application data in a local RDB store on a device to other divices that form a Super Device.
7
8
9## Basic Concepts
10
11OpenHamony supports synchronization of the relational data of an application across multiple devices.
12
13- Distributed table list<br>After a table is created for an application in an RDB store, you can set it as a distributed table. When querying the RDB store of a remote device, you can obtain the distributed table name of the remote device based on the local table name.
14
15- Synchronization mode<br>Data can be synchronized 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 Synchronization Mechanism
24
25![relationalStore_sync](figures/relationalStore_sync.jpg)
26
27After writing data to an RDB store, the service sends a synchronization request to the **DatamgrService**.
28
29The **DatamgrService** reads the data to be synchronized 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 synchronized 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
48## Available APIs
49
50Most of the APIs for cross-device data synchronization of RDB stores are executed asynchronously in callback or promise mode. 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).
51
52| API| Description|
53| -------- | -------- |
54| setDistributedTables(tables: Array&lt;string&gt;, callback: AsyncCallback&lt;void&gt;): void | Sets the distributed tables to be synchronized.|
55| sync(mode: SyncMode, predicates: RdbPredicates, callback: AsyncCallback&lt;Array&lt;[string, number]&gt;&gt;): void | Synchronizes data across devices.|
56| on(event: 'dataChange', type: SubscribeType, observer: Callback&lt;Array&lt;string&gt;&gt;): void | Subscribes to changes in the distributed data.|
57| off(event:'dataChange', type: SubscribeType, observer: Callback&lt;Array&lt;string&gt;&gt;): void | Unsubscribe from changes in the distributed data.|
58| obtainDistributedTableName(device: string, table: string, callback: AsyncCallback&lt;string&gt;): void; | Obtains the table name on the specified device based on the local table name.|
59| remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array&lt;string&gt; , callback: AsyncCallback&lt;ResultSet&gt;): void | Queries data from the RDB store of a remote device based on specified conditions.|
60
61
62## How to Develop
63
64> **NOTE**
65>
66> The security level of the destination device (to which data is synchronized) cannot be higher than that of the source device. For details, see [Access Control Mechanism in Cross-Device Synchronization](access-control-by-device-and-data-level.md#access-control-mechanism-in-cross-device-synchronization).
67
681. Import the module.
69
70   ```ts
71   import relationalStore from '@ohos.data.relationalStore';
72   ```
73
742. Request permissions.
75
76   1. Declare the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md).
77   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).
78
793. Create an RDB store and set a table for distributed synchronization.
80
81   ```ts
82   import UIAbility from '@ohos.app.ability.UIAbility';
83   import window from '@ohos.window';
84   import { BusinessError } from "@ohos.base";
85
86   class EntryAbility extends UIAbility {
87     onWindowStageCreate(windowStage: window.WindowStage) {
88       const STORE_CONFIG: relationalStore.StoreConfig = {
89         name: "RdbTest.db",
90         securityLevel: relationalStore.SecurityLevel.S1
91       };
92
93       relationalStore.getRdbStore(this.context, STORE_CONFIG, (err: BusinessError, store: relationalStore.RdbStore) => {
94         store.executeSql('CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER, SALARY REAL, CODES BLOB)', (err) => {
95           // Set the table for distributed synchronization.
96           store.setDistributedTables(['EMPLOYEE']);
97           // Perform related operations.
98         })
99       })
100     }
101   }
102   ```
103
1044. Synchronize data across devices. After **sync()** is called to trigger a synchronization, data is synchronized from the local device to all other devices on the network.
105
106   ```ts
107   // Construct the predicate object for synchronizing the distributed table.
108   let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
109   // Call sync() to synchronize data.
110   if(store != undefined)
111   {
112     (store as relationalStore.RdbStore).sync(relationalStore.SyncMode.SYNC_MODE_PUSH, predicates, (err, result) => {
113       // Check whether data synchronization is successful.
114       if (err) {
115         console.error(`Failed to sync data. Code:${err.code},message:${err.message}`);
116         return;
117       }
118       console.info('Succeeded in syncing data.');
119       for (let i = 0; i < result.length; i++) {
120         console.info(`device:${result[i][0]},status:${result[i][1]}`);
121       }
122     })
123   }
124   ```
125
1265. Subscribe to changes in the distributed data. The data synchronization triggers the **observer** callback registered in **on()**. The input parameter of the callback is the ID of the device whose data changes.
127
128   ```ts
129   let devices: string | undefined = undefined;
130   try {
131     // Register an observer to listen for the changes of the distributed data.
132     // When data in the RDB store changes, the registered callback will be invoked to return the data changes.
133     if(store != undefined) {
134       (store as relationalStore.RdbStore).on('dataChange', relationalStore.SubscribeType.SUBSCRIBE_TYPE_REMOTE, (storeObserver)=>{
135         if(devices != undefined){
136           for (let i = 0; i < devices.length; i++) {
137             console.info(`The data of device:${devices[i]} has been changed.`);
138           }
139         }
140       });
141     }
142   } catch (err) {
143     console.error('Failed to register observer. Code:${err.code},message:${err.message}');
144   }
145   // You can unsubscribe from the data changes if required.
146   try {
147     if(store != undefined) {
148       (store as relationalStore.RdbStore).off('dataChange', relationalStore.SubscribeType.SUBSCRIBE_TYPE_REMOTE, (storeObserver)=>{
149       });
150     }
151   } catch (err) {
152     console.error('Failed to register observer. Code:${err.code},message:${err.message}');
153   }
154   ```
155
1566. Query data across devices. If data synchronization is not complete or triggered, an application can call **remoteQuery()** to query data from a remote device.
157
158   > **NOTE**
159   >
160   > The value of **deviceIds** can be obtained by using [deviceManager.getAvailableDeviceListSync](../reference/apis-distributedservice-kit/js-apis-distributedDeviceManager.md#getavailabledevicelistsync) method.
161
162
163   ```ts
164   // Obtain device IDs.
165   import deviceManager from '@ohos.distributedDeviceManager';
166   import { BusinessError } from '@ohos.base'
167
168   let dmInstance: deviceManager.DeviceManager;
169   let deviceId: string | undefined = undefined ;
170
171   try {
172     dmInstance = deviceManager.createDeviceManager("com.example.appdatamgrverify");
173     let devices = dmInstance.getAvailableDeviceListSync();
174
175     deviceId = devices[0].networkId;
176
177     // Construct a predicate object for querying the distributed table.
178     let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
179     // Query data from the specified remote device and return the query result.
180     if(store != undefined && deviceId != undefined) {
181       (store as relationalStore.RdbStore).remoteQuery(deviceId, 'EMPLOYEE', predicates, ['ID', 'NAME', 'AGE', 'SALARY', 'CODES'],
182         (err: BusinessError, resultSet: relationalStore.ResultSet) => {
183           if (err) {
184             console.error(`Failed to remoteQuery data. Code:${err.code},message:${err.message}`);
185             return;
186           }
187           console.info(`ResultSet column names: ${resultSet.columnNames}, column count: ${resultSet.columnCount}`);
188         }
189       )
190     }
191   } catch (err) {
192     let code = (err as BusinessError).code;
193     let message = (err as BusinessError).message;
194     console.error("createDeviceManager errCode:" + code + ",errMessage:" + message);
195   }
196   ```