diff --git a/zh-cn/application-dev/database/Readme-CN.md b/zh-cn/application-dev/database/Readme-CN.md index 9dedd234837cd5f5fa13d4f34525c4849fcb67fe..bbcae8eed48259274e90eae0bd57cc53dd263acd 100644 --- a/zh-cn/application-dev/database/Readme-CN.md +++ b/zh-cn/application-dev/database/Readme-CN.md @@ -1,17 +1,22 @@ # 数据管理 -- 分布式数据服务 - - [分布式数据服务概述](database-mdds-overview.md) - - [分布式数据服务开发指导](database-mdds-guidelines.md) -- 关系型数据库 - - [关系型数据库概述](database-relational-overview.md) - - [关系型数据库开发指导](database-relational-guidelines.md) -- 首选项 - - [首选项概述](database-preference-overview.md) - - [首选项开发指导](database-preference-guidelines.md) -- 分布式数据对象 - - [分布式数据对象概述](database-distributedobject-overview.md) - - [分布式数据对象开发指导](database-distributedobject-guidelines.md) -- 数据共享 - - [数据共享概述](database-datashare-overview.md) - - [数据共享开发指导](database-datashare-guidelines.md) +- [数据管理概述](data-mgmt-overview.md) +- 应用数据持久化 + - [应用数据持久化概述](app-data-persistence-overview.md) + - [通过用户首选项实现数据持久化](data-persistence-by-preferences.md) + - [通过键值型数据库实现数据持久化](data-persistence-by-kv-store.md) + - [通过关系型数据库实现数据持久化](data-persistence-by-rdb-store.md) +- 同应用跨设备数据同步(分布式) + - [同应用跨设备数据同步概述](sync-app-data-across-devices-overview.md) + - [键值型数据库跨设备数据同步](data-sync-of-kv-store.md) + - [关系型数据库跨设备数据同步](data-sync-of-rdb-store.md) + - [分布式数据对象跨设备数据同步](data-sync-of-distributed-data-object.md) +- 数据可靠性与安全性 + - [数据可靠性与安全性概述](data-reliability-security-overview.md) + - [数据库备份与恢复](data-backup-and-restore.md) + - [数据库加密](data-encryption.md) + - [基于设备分类和数据分级的访问控制](access-control-by-device-and-data-level.md) +- 同设备跨应用数据共享(仅对系统应用开放) + - [同设备跨应用数据共享概述](share-device-data-across-apps-overview.md) + - [通过DataShareExtensionAbility实现数据共享](share-data-by-datashareextensionability.md) + - [通过静默数据访问实现数据共享](share-data-by-silent-access.md) diff --git a/zh-cn/application-dev/database/access-control-by-device-and-data-level.md b/zh-cn/application-dev/database/access-control-by-device-and-data-level.md new file mode 100644 index 0000000000000000000000000000000000000000..f11be63746c212517949e27ec56a067b911a5427 --- /dev/null +++ b/zh-cn/application-dev/database/access-control-by-device-and-data-level.md @@ -0,0 +1,122 @@ +# 基于设备分类和数据分级的访问控制 + + +## 基本概念 + +分布式数据管理对数据实施分类分级保护,提供基于数据安全标签以及设备安全等级的访问控制机制。 + +数据安全标签和设备安全等级越高,加密措施和访问控制措施越严格,数据安全性越高。 + + +### 数据安全标签 + +按照数据分类分级规范要求,可将数据分为S1、S2、S3、S4四个安全等级。 + + | 风险等级 | 风险标准 | 定义 | 样例 | +| -------- | -------- | -------- | -------- | +| 严重 | S4 | 业界法律法规定义的特殊数据类型,涉及个人的最私密领域的信息或一旦泄露、篡改、破坏、销毁可能会给个人或组织造成重大的不利影响的数据。 | 政治观点、宗教和哲学信仰、工会成员资格、基因数据、生物信息、健康和性生活状况,性取向等或设备认证鉴权、个人信用卡等财物信息等。 | +| 高 | S3 | 数据的泄露、篡改、破坏、销毁可能会给个人或组织导致严峻的不利影响 | 个人实时精确定位信息、运动轨迹等。 | +| 中 | S2 | 数据的泄露、篡改、破坏、销毁可能会给个人或组织导致严重的不利影响 | 个人的详细通信地址、姓名昵称等。 | +| 低 | S1 | 数据的泄露、篡改、破坏、销毁可能会给个人或组织导致有限的不利影响 | 性别、国籍、用户申请记录等。 | + + +### 设备安全等级 + +根据设备安全能力,比如是否有TEE、是否有安全存储芯片等,将设备安全等级分为SL1、SL2、SL3、SL4、SL5五个等级。例如,开发板rk3568、hi3516为低安全的SL1设备,平板通常为高安全的SL4设备。 + +在设备组网时可以通过`hidumper -s 3511`查看设备安全等级,例如,rk3568设备的安全等级查询如下: + +![zh-cn_image_0000001542496993](figures/zh-cn_image_0000001542496993.png) + + +## 跨设备同步访问控制机制 + +数据跨设备同步时,数据管理基于数据安全标签和设备安全等级进行访问控制。规则为,在本设备的数据安全标签不高于对端设备的设备安全等级时,数据才能从本设备同步到对端设备,否则不能同步。具体访问控制矩阵如下: + +|设备安全级别|可同步的数据安全标签| +|---|---| +|SL1|S1| +|SL2|S1~S2| +|SL3|S1~S3| +|SL4|S1~S4| +|SL5|S1~S4| + +例如,对于类似rk3568、hi3516的开发板设备,设备安全等级为SL1。若创建数据安全标签为S1的数据库,则此数据库数据可以在这些设备间同步;若创建的数据库标签为S2-S4,则不能在这些设备间同步。 + + +## 场景介绍 + +分布式数据库的访问控制机制确保了数据存储和同步时的安全能力。在创建数据库时,应当基于数据分类分级规范合理地设置数据库的安全标签,确保数据库内容和数据标签的一致性。 + + +## 使用键值型数据库实现数据分级 + +键值型数据库,通过securityLevel参数设置数据库的安全等级。此处以创建安全等级为S1的数据库为例。 + +具体接口及功能,可见[分布式键值数据库](../reference/apis/js-apis-distributedKVStore.md)。 + + + +```js +import distributedKVStore from '@ohos.data.distributedKVStore'; + +let kvManager; +let context = getContext(this); +const kvManagerConfig = { + context: context, + bundleName: 'com.example.datamanagertest' +} +try { + kvManager = distributedKVStore.createKVManager(kvManagerConfig); + console.info('Succeeded in creating KVManager.'); +} catch (e) { + console.error(`Failed to create KVManager. Code:${e.code},message:${e.message}`); +} +let kvStore; +try { + const options = { + createIfMissing: true, + encrypt: true, + backup: false, + autoSync: true, + kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, + securityLevel: distributedKVStore.SecurityLevel.S1 + }; + kvManager.getKVStore('storeId', options, (err, store) => { + if (err) { + console.error(`Failed to get KVStore. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in getting KVStore.'); + kvStore = store; + }); +} catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); +} +``` + + +## 使用关系型数据库实现数据分级 + +关系型数据库,通过securityLevel参数设置数据库的安全等级。此处以创建安全等级为S1的数据库为例。 + +具体接口及功能,可见[关系型数据库](../reference/apis/js-apis-data-relationalStore.md)。 + + + +```js +import relationalStore from '@ohos.data.relationalStore'; + +let store; +const STORE_CONFIG = { + name: 'RdbTest.db', + securityLevel: relationalStore.SecurityLevel.S1 +}; +let promise = relationalStore.getRdbStore(this.context, STORE_CONFIG); +promise.then(async (rdbStore) => { + store = rdbStore; + console.info('Succeeded in getting RdbStore.') +}).catch((err) => { + console.error(`Failed to get RdbStore. Code:${err.code},message:${err.message}`); +}) +``` diff --git a/zh-cn/application-dev/database/app-data-persistence-overview.md b/zh-cn/application-dev/database/app-data-persistence-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..f15df4be391692c32365a79e5454bd627d9fc80b --- /dev/null +++ b/zh-cn/application-dev/database/app-data-persistence-overview.md @@ -0,0 +1,17 @@ +# 应用数据持久化概述 + + +应用数据持久化,是指应用将内存中的数据通过文件或数据库的形式保存到设备上。内存中的数据形态通常是任意的数据结构或数据对象,存储介质上的数据形态可能是文本、数据库、二进制文件等。 + + +OpenHarmony标准系统支持典型的存储数据形态,包括用户首选项、键值型数据库、关系型数据库。 + + +开发者可以根据如下功能介绍,选择合适的数据形态以满足自己应用数据的持久化需要。 + + +- **用户首选项(Preferences)**:通常用于保存应用的配置信息。数据通过文本的形式保存在设备中,应用使用过程中会将文本中的数据全量加载到内存中,所以访问速度快、效率高,但不适合需要存储大量数据的场景。 + +- **键值型数据库(KV-Store)**:一种非关系型数据库,其数据以“键值”对的形式进行组织、索引和存储,其中“键”作为唯一标识符。适合很少数据关系和业务关系的业务数据存储,同时因其在分布式场景中降低了解决数据库版本兼容问题的复杂度,和数据同步过程中冲突解决的复杂度而被广泛使用。相比于关系型数据库,更容易做到跨设备跨版本兼容。 + +- **关系型数据库(RelationalStore)**:一种关系型数据库,以行和列的形式存储数据,广泛用于应用中的关系型数据的处理,包括一系列的增、删、改、查等接口,开发者也可以运行自己定义的SQL语句来满足复杂业务场景的需要。 diff --git a/zh-cn/application-dev/database/data-backup-and-restore.md b/zh-cn/application-dev/database/data-backup-and-restore.md new file mode 100644 index 0000000000000000000000000000000000000000..425b18edcba35371d9a011bc2d817c47cb3807b8 --- /dev/null +++ b/zh-cn/application-dev/database/data-backup-and-restore.md @@ -0,0 +1,231 @@ +# 数据库备份与恢复 + + +## 场景介绍 + +当应用在处理一项重要的操作,显然是不能被打断的。例如:写入多个表关联的事务。此时,每个表的写入都是单独的,但是表与表之间的事务关联性不能被分割。 + +如果操作的过程中出现问题,开发者可以使用恢复功能,将数据库恢复到之前的状态,重新对数据库进行操作。 + +在数据库被篡改、删除、或者设备断电场景下,数据库可能会因为数据丢失、数据损坏、脏数据等而不可用,可以通过数据库的备份恢复能力将数据库恢复至可用状态。 + + +键值型数据库和关系型数据库均支持对数据库的备份和恢复。另外,键值型数据库还支持删除数据库备份,以释放本地存储空间。 + + +## 键值型数据库备份、恢复与删除 + +键值型数据库,通过backup接口实现数据库备份,通过restore接口实现数据库恢复,通过deletebackup接口删除数据库备份。具体接口及功能,可见[分布式键值数据库](../reference/apis/js-apis-distributedKVStore.md)。 + +1. 创建数据库。 + + (1) 创建kvManager。 + + (2) 配置数据库参数。 + + (3) 创建kvStore。 + + + ```js + import distributedKVStore from '@ohos.data.distributedKVStore'; + + let kvManager; + let context = getContext(this); + const kvManagerConfig = { + context: context, + bundleName: 'com.example.datamanagertest' + } + try { + kvManager = distributedKVStore.createKVManager(kvManagerConfig); + console.info('Succeeded in creating KVManager.'); + } catch (e) { + console.error(`Failed to create KVManager. Code:${e.code},message:${e.message}`); + } + let kvStore; + try { + const options = { + createIfMissing: true, + encrypt: false, + backup: false, + autoSync: true, + kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, + securityLevel: distributedKVStore.SecurityLevel.S2 + }; + kvManager.getKVStore('storeId', options, (err, store) => { + if (err) { + console.error(`Fail to get KVStore. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in getting KVStore.'); + kvStore = store; + }); + } catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); + } + ``` + +2. 使用put()方法插入数据。 + + ```js + const KEY_TEST_STRING_ELEMENT = 'key_test_string'; + const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; + try { + kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => { + if (err !== undefined) { + console.error(`Fail to put data. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in putting data.'); + }); + } catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); + } + ``` + +3. 使用backup()方法备份数据。 + + ```js + let file = 'BK001'; + try { + kvStore.backup(file, (err) => { + if (err) { + console.error(`Fail to backup data.code:${err.code},message:${err.message}`); + } else { + console.info('Succeeded in backupping data.'); + } + }); + } catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); + } + ``` + +4. 使用delete()方法删除数据(模拟意外删除、篡改场景)。 + + ```js + try { + kvStore.delete(KEY_TEST_STRING_ELEMENT, (err) => { + if (err !== undefined) { + console.error(`Fail to delete data. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in deleting data.'); + }); + } catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); + } + ``` + +5. 使用restore()方法恢复数据。 + + ```js + let file = 'BK001'; + try { + kvStore.restore(file, (err) => { + if (err) { + console.error(`Fail to restore data. Code:${err.code},message:${err.message}`); + } else { + console.info('Succeeded in restoring data.'); + } + }); + } catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); + } + ``` + +6. 当本地设备存储空间有限或需要重新备份时,还可使用deleteBackup()方法删除备份,释放存储空间。 + + ```js + let kvStore; + let files = ['BK001']; + try { + kvStore.deleteBackup(files).then((data) => { + console.info(`Succeed in deleting Backup. Data:filename is ${data[0]},result is ${data[1]}.`); + }).catch((err) => { + console.error(`Fail to delete Backup. Code:${err.code},message:${err.message}`); + }) + } catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); + } + ``` + + +## 关系型数据库备份与恢复 + +关系型数据库,通过backup接口实现数据库备份,通过restore接口实现数据库恢复。具体接口及功能,可见[关系型数据库](../reference/apis/js-apis-data-relationalStore.md)。 + +1. 使用getRdbStore()方法创建关系型数据库。 + + ```js + import relationalStore from '@ohos.data.relationalStore'; + + let store; + let context = getContext(this); + const STORE_CONFIG = { + name: 'RdbTest.db', + securityLevel: relationalStore.SecurityLevel.S1 + }; + relationalStore.getRdbStore(context, STORE_CONFIG, (err, rdbStore) => { + store = rdbStore; + if (err) { + console.error(`Failed to get RdbStore. Code:${err.code},message:${err.message}`); + return; + } + store.executeSql("CREATE TABLE IF NOT EXISTS EMPLOYEE (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER, salary INTEGER, codes Uint8Array);", null); + console.info('Succeeded in getting RdbStore.'); + }) + ``` + +2. 使用insert()方法插入数据。 + + ```js + const valueBucket = { + 'NAME': 'Lisa', + 'AGE': 18, + 'SALARY': 100.5, + 'CODES': new Uint8Array([1, 2, 3, 4, 5]) + }; + store.insert('EMPLOYEE', valueBucket, relationalStore.ConflictResolution.ON_CONFLICT_REPLACE, (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}`); + }) + ``` + +3. 使用backup()方法备份数据。 + + ```js + store.backup('dbBackup.db', (err) => { + if (err) { + console.error(`Failed to backup data. Code:${err.code},message:${err.message}`); + return; + } + console.info(`Succeeded in backuping data.`); + }) + ``` + +4. 使用delete()方法删除数据(模拟意外删除、篡改场景)。 + + ```js + let predicates = new relationalStore.RdbPredicates('EMPLOYEE'); + predicates.equalTo('NAME', 'Lisa'); + let promise = store.delete(predicates); + promise.then((rows) => { + console.info(`Delete rows: ${rows}`); + }).catch((err) => { + console.error(`Failed to delete data. Code:${err.code},message:${err.message}`); + }) + ``` + +5. 使用restore()方法恢复数据。 + + ```js + store.restore('dbBackup.db', (err) => { + if (err) { + console.error(`Failed to restore data. Code:${err.code},message:${err.message}`); + return; + } + console.info(`Succeeded in restoring data.`); + }) + ``` diff --git a/zh-cn/application-dev/database/data-encryption.md b/zh-cn/application-dev/database/data-encryption.md new file mode 100644 index 0000000000000000000000000000000000000000..077168ea5d0c5ccba4574f15e81d07d56ceadad2 --- /dev/null +++ b/zh-cn/application-dev/database/data-encryption.md @@ -0,0 +1,85 @@ +# 数据库加密 + + +## 场景介绍 + +为了增强数据库的安全性,数据库提供了一个安全适用的数据库加密能力,从而对数据库存储的内容实施有效保护。通过数据库加密等安全方法实现了数据库数据存储的保密性和完整性要求,使得数据库以密文方式存储并在密态方式下工作,确保了数据安全。 + +加密后的数据库只能通过接口进行访问,无法通过其它方式打开数据库文件。数据库的加密属性在创建数据库时确认,无法变更。 + +键值型数据库和关系型数据库均支持数据库加密操作。 + + +## 键值型数据库加密 + +键值型数据库,通过options中encrypt参数来设置是否加密,默认为false,表示不加密。encrypt参数为true时表示加密。 + +具体接口及功能,可见[分布式键值数据库](../reference/apis/js-apis-distributedKVStore.md)。 + + +```js +import distributedKVStore from '@ohos.data.distributedKVStore'; + +let kvManager; +let context = getContext(this); +const kvManagerConfig = { + context: context, + bundleName: 'com.example.datamanagertest', +} +try { + kvManager = distributedKVStore.createKVManager(kvManagerConfig); + console.info('Succeeded in creating KVManager.'); +} catch (e) { + console.error(`Failed to create KVManager. Code:${e.code},message:${e.message}`); +} +let kvStore; +try { + const options = { + createIfMissing: true, + // 设置数据库加密 + encrypt: true, + backup: false, + autoSync: true, + kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, + securityLevel: distributedKVStore.SecurityLevel.S2 + }; + kvManager.getKVStore('storeId', options, (err, store) => { + if (err) { + console.error(`Fail to get KVStore. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in getting KVStore.'); + kvStore = store; + }); +} catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); +} +``` + + +## 关系型数据库加密 + +关系型数据库,通过StoreConfig中encrypt属性来设置是否加密,默认为false,表示不加密。encrypt参数为true时表示加密。 + +具体接口及功能,可见[关系型数据库](../reference/apis/js-apis-data-relationalStore.md)。 + + +```js +import relationalStore from '@ohos.data.relationalStore'; + +let store; +let context = getContext(this); +const STORE_CONFIG = { + name: 'RdbTest.db', + securityLevel: relationalStore.SecurityLevel.S1, + encrypt: true +}; +relationalStore.getRdbStore(context, STORE_CONFIG, (err, rdbStore) => { + store = rdbStore; + if (err) { + console.error(`Failed to get RdbStore. Code:${err.code},message:${err.message}`); + return; + } + console.info(`Succeeded in getting RdbStore.`); +}) +``` diff --git a/zh-cn/application-dev/database/data-mgmt-overview.md b/zh-cn/application-dev/database/data-mgmt-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..0f5bb73edd8b584210af07c5d278aaa218b1d379 --- /dev/null +++ b/zh-cn/application-dev/database/data-mgmt-overview.md @@ -0,0 +1,36 @@ +# 数据管理概述 + + +## 功能介绍 + +数据管理为开发者提供数据存储、数据管理和数据同步能力,比如联系人应用数据可以保存到数据库中,提供数据库的安全、可靠以及共享访问等管理机制,也支持与手表同步联系人信息。 + +- 数据存储:提供通用数据持久化能力,根据数据特点,分为用户首选项、键值型数据库和关系型数据库。 + +- 数据管理:提供高效的数据管理能力,包括权限管理、数据备份恢复、数据共享框架等。 + +- 数据同步:提供跨设备数据同步能力,比如分布式对象支持内存对象跨设备共享能力,分布式数据库支持跨设备数据库访问能力。 + +应用创建的数据库,都保存到应用沙盒,当应用卸载时,数据库也会自动删除。 + + +## 运作机制 + +数据管理模块包括用户首选项、键值型数据管理、关系型数据管理、分布式数据对象和跨应用数据管理。Interface接口层提供标准JS API接口,定义这些部件接口描述,供开发者参考。Frameworks&System service层负责实现部件数据存储、同步功能,还有一些SQLite和其他子系统的依赖。 + + **图1** 数据管理架构图   + +![dataManagement](figures/dataManagement.jpg) + + +- 用户首选项(Preferences):提供了轻量级配置数据的持久化能力,并支持订阅数据变化的通知能力。不支持分布式同步,常用于保存应用配置信息、用户偏好设置等。 + +- 键值型数据管理(KV-Store):提供了键值型数据库的读写、加密、手动备份以及订阅通知能力。应用需要使用键值型数据库的分布式能力时,KV-Store会将同步请求发送给DatamgrService由其完成跨设备数据同步。 + +- 关系型数据管理(RelationalStore):提供了关系型数据库的增删改查、加密、手动备份以及订阅通知能力。应用需要使用关系型数据库的分布式能力时,RelationalStore部件会将同步请求发送给DatamgrService由其完成跨设备数据同步。 + +- 分布式数据对象(DataObject):独立提供对象型结构数据的分布式能力。如果应用需要重启后仍获取之前的对象数据(包含跨设备应用和本设备应用),则使用数据管理服务(DatamgrService)的对象持久化能力,做暂时保存。 + +- 跨应用数据管理(DataShare):提供了数据提供者provider、数据消费者consumer以及同设备跨应用数据交互的增、删、改、查以及订阅通知等能力。DataShare不与任何数据库绑定,可以对接关系型数据库、键值型数据库。如果开发C/C++应用甚至可以自行封装数据库。在提供标准的provider-consumer模式基础上,同时提供了静默数据访问能力,即不再拉起provider而是直接通过DatamgrService代理访问provider的数据(目前仅关系型数据库支持静默数据访问方式)。 + +- 数据管理服务(DatamgrService):提供其它部件的同步及跨应用共享能力,包括RelationalStore和KV-Store跨设备同步,DataShare静默访问provider数据,暂存DataObject同步对象数据等。 diff --git a/zh-cn/application-dev/database/data-persistence-by-kv-store.md b/zh-cn/application-dev/database/data-persistence-by-kv-store.md new file mode 100644 index 0000000000000000000000000000000000000000..06371748f4c1d5f1d3ea15e0e0099bfe54c4fe2f --- /dev/null +++ b/zh-cn/application-dev/database/data-persistence-by-kv-store.md @@ -0,0 +1,189 @@ +# 通过键值型数据库实现数据持久化 + + +## 场景介绍 + +键值型数据库存储键值对形式的数据,当需要存储的数据没有复杂的关系模型,比如存储商品名称及对应价格、员工工号及今日是否已出勤等,由于数据复杂度低,更容易兼容不同数据库版本和设备类型,因此推荐使用键值型数据库持久化此类数据。 + + +## 约束限制 + +- 设备协同数据库,针对每条记录,Key的长度≤896 Byte,Value的长度<4 MB。 + +- 单版本数据库,针对每条记录,Key的长度≤1 KB,Value的长度<4 MB。 + +- 每个应用程序最多支持同时打开16个分布式数据库。 + +- 键值型数据库事件回调方法中不允许进行阻塞操作,例如修改UI组件。 + + +## 接口说明 + +以下是键值型数据库持久化功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见[分布式键值数据库](../reference/apis/js-apis-distributedKVStore.md)。 + +| 接口名称 | 描述 | +| -------- | -------- | +| createKVManager(config: KVManagerConfig): KVManager | 创建一个KVManager对象实例,用于管理数据库对象。 | +| getKVStore<T>(storeId: string, options: Options, callback: AsyncCallback<T>): void | 指定Options和storeId,创建并得到指定类型的KVStore数据库。 | +| put(key: string, value: Uint8Array\|string\|number\|boolean, callback: AsyncCallback<void>): void | 添加指定类型的键值对到数据库。 | +| get(key: string, callback: AsyncCallback<Uint8Array\|string\|boolean\|number>): void | 获取指定键的值。 | +| delete(key: string, callback: AsyncCallback<void>): void | 从数据库中删除指定键值的数据。 | + + +## 开发步骤 + +1. 若要使用键值型数据库,首先要获取一个KVManager实例,用于管理数据库对象。示例代码如下所示: + + Stage模型示例: + + + ```js + // 导入模块 + import distributedKVStore from '@ohos.data.distributedKVStore'; + + // Stage模型 + import UIAbility from '@ohos.app.ability.UIAbility'; + + let kvManager; + + export default class EntryAbility extends UIAbility { + onCreate() { + let context = this.context; + const kvManagerConfig = { + context: context, + bundleName: 'com.example.datamanagertest' + }; + try { + // 创建KVManager实例 + kvManager = distributedKVStore.createKVManager(kvManagerConfig); + console.info('Succeeded in creating KVManager.'); + // 继续创建获取数据库 + } catch (e) { + console.error(`Failed to create KVManager. Code:${e.code},message:${e.message}`); + } + } + } + ``` + + FA模型示例: + + + ```js + // 导入模块 + import distributedKVStore from '@ohos.data.distributedKVStore'; + + // FA模型 + import featureAbility from '@ohos.ability.featureAbility'; + + let kvManager; + let context = featureAbility.getContext(); // 获取context + const kvManagerConfig = { + context: context, + bundleName: 'com.example.datamanagertest' + }; + try { + kvManager = distributedKVStore.createKVManager(kvManagerConfig); + console.info('Succeeded in creating KVManager.'); + // 继续创建获取数据库 + } catch (e) { + console.error(`Failed to create KVManager. Code:${e.code},message:${e.message}`); + } + ``` + +2. 创建并获取键值数据库。示例代码如下所示: + + ```js + try { + const options = { + createIfMissing: true, // 当数据库文件不存在时是否创建数据库,默认创建 + encrypt: false, // 当数据库文件不存在时是否创建数据库,默认创建 + backup: false, // 设置数据库文件是否备份,默认备份 + autoSync: true, // 设置数据库文件是否自动同步。默认为false,即手动同步;设置为true时,表示自动同步 + kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, // 设置要创建的数据库类型,默认为多设备协同数据库 + securityLevel: distributedKVStore.SecurityLevel.S2 // 设置数据库安全级别 + }; + // storeId为数据库唯一标识符 + kvManager.getKVStore('storeId', options, (err, kvStore) => { + if (err) { + console.error(`Failed to get KVStore. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in getting KVStore.'); + // 进行相关数据操作 + }); + } catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); + } + ``` + +3. 调用put()方法向键值数据库中插入数据。示例代码如下所示: + + ```js + const KEY_TEST_STRING_ELEMENT = 'key_test_string'; + const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; + try { + kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => { + if (err !== undefined) { + console.error(`Failed to put data. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in putting data.'); + }); + } catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); + } + ``` + + > **说明:** + > + > 当Key值存在时,put()方法会修改其值,否则新增一条数据。 + +4. 调用get()方法获取指定键的值。示例代码如下所示: + + ```js + const KEY_TEST_STRING_ELEMENT = 'key_test_string'; + const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; + try { + kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => { + if (err !== undefined) { + console.error(`Failed to put data. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in putting data.'); + kvStore.get(KEY_TEST_STRING_ELEMENT, (err, data) => { + if (err !== undefined) { + console.error(`Failed to get data. Code:${err.code},message:${err.message}`); + return; + } + console.info(`Succeeded in getting data. data:${data}`); + }); + }); + } catch (e) { + console.error(`Failed to get data. Code:${e.code},message:${e.message}`); + } + ``` + +5. 调用delete()方法删除指定键值的数据。示例代码如下所示: + + ```js + const KEY_TEST_STRING_ELEMENT = 'key_test_string'; + const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; + try { + kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => { + if (err !== undefined) { + console.error(`Failed to put data. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in putting data.'); + kvStore.delete(KEY_TEST_STRING_ELEMENT, (err) => { + if (err !== undefined) { + console.error(`Failed to delete data. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in deleting data.'); + }); + }); + } catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); + } + ``` diff --git a/zh-cn/application-dev/database/data-persistence-by-preferences.md b/zh-cn/application-dev/database/data-persistence-by-preferences.md new file mode 100644 index 0000000000000000000000000000000000000000..86ad970f3e63be7280123908ca961fcb2c07995f --- /dev/null +++ b/zh-cn/application-dev/database/data-persistence-by-preferences.md @@ -0,0 +1,256 @@ +# 通过用户首选项实现数据持久化 + + +## 场景介绍 + +用户首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。当用户希望有一个全局唯一存储的地方,可以采用用户首选项来进行存储。Preferences会将该数据缓存在内存中,当用户读取的时候,能够快速从内存中获取数据。Preferences会随着存放的数据量越多而导致应用占用的内存越大,因此,Preferences不适合存放过多的数据,适用的场景一般为应用保存用户的个性化设置(字体大小,是否开启夜间模式)等。 + + +## 运作机制 + +如图所示,用户程序通过JS接口调用用户首选项读写对应的数据文件。开发者可以将用户首选项持久化文件的内容加载到Preferences实例,每个文件唯一对应到一个Preferences实例,系统会通过静态容器将该实例存储在内存中,直到主动从内存中移除该实例或者删除该文件。 + + **图1** 用户首选项运作机制   + +![preferences](figures/preferences.jpg) + + +## 约束限制 + +- Key键为string类型,要求非空且长度不超过80个字节。 + +- 如果Value值为string类型,可以为空,不为空时长度不超过8192个字节。 + +- 内存会随着存储数据量的增大而增大,所以存储的数据量应该是轻量级的,建议存储的数据不超过一万条,否则会在内存方面产生较大的开销。 + + +## 接口说明 + +以下是用户首选项持久化功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见[用户首选项](../reference/apis/js-apis-data-preferences.md)。 + + | 接口名称 | 描述 | +| -------- | -------- | +| getPreferences(context: Context, name: string, callback: AsyncCallback<Preferences>): void | 获取Preferences实例。 | +| put(key: string, value: ValueType, callback: AsyncCallback<void>): void | 将数据写入Preferences实例,可通过flush将Preferences实例持久化。 | +| has(key: string, callback: AsyncCallback<boolean>): void | 检查Preferences实例是否包含名为给定Key的存储键值对。给定的Key值不能为空。 | +| get(key: string, defValue: ValueType, callback: AsyncCallback<ValueType>): void | 获取键对应的值,如果值为null或者非默认值类型,返回默认数据defValue。 | +| delete(key: string, callback: AsyncCallback<void>): void | 从Preferences实例中删除名为给定Key的存储键值对。 | +| flush(callback: AsyncCallback<void>): void | 将当前Preferences实例的数据异步存储到用户首选项持久化文件中。 | +| on(type: 'change', callback: Callback<{ key : string }>): void | 订阅数据变更,订阅的Key的值发生变更后,在执行flush方法后,触发callback回调。 | +| off(type: 'change', callback?: Callback<{ key : string }>): void | 取消订阅数据变更。 | +| deletePreferences(context: Context, name: string, callback: AsyncCallback<void>): void | 从内存中移除指定的Preferences实例。若Preferences实例有对应的持久化文件,则同时删除其持久化文件。 | + + +## 开发步骤 + +1. 导入`@ohos.data.preferences`模块。 + + ```js + import dataPreferences from '@ohos.data.preferences'; + ``` + +2. 要通过用户首选项实现数据持久化,首先要获取Preferences实例。读取指定文件,将数据加载到Preferences实例,用于数据操作。 + + Stage模型示例: + + + ```js + import UIAbility from '@ohos.app.ability.UIAbility'; + + class EntryAbility extends UIAbility { + onWindowStageCreate(windowStage) { + try { + dataPreferences.getPreferences(this.context, 'mystore', (err, preferences) => { + if (err) { + console.error(`Failed to get preferences. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in getting preferences.'); + // 进行相关数据操作 + }) + } catch (err) { + console.error(`Failed to get preferences. Code:${err.code},message:${err.message}`); + } + } + } + ``` + + FA模型示例: + + + ```js + import featureAbility from '@ohos.ability.featureAbility'; + + // 获取context + let context = featureAbility.getContext(); + + try { + dataPreferences.getPreferences(context, 'mystore', (err, preferences) => { + if (err) { + console.error(`Failed to get preferences. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in getting preferences.'); + // 进行相关数据操作 + }) + } catch (err) { + console.error(`Failed to get preferences. Code is ${err.code},message:${err.message}`); + } + ``` + +3. 写入数据。 + + 使用put()方法保存数据到缓存的Preferences实例中。在写入数据后,如有需要,可使用flush()方法将Preferences实例的数据存储到持久化文件。 + + > **说明:** + > + > 当对应的键已经存在时,put()方法会修改其值。如果仅需要在键值对不存在时新增键值对,而不修改已有键值对,需使用has()方法检查是否存在对应键值对;如果不关心是否会修改已有键值对,则直接使用put()方法即可。 + + 示例代码如下所示: + + + ```js + try { + preferences.has('startup', function (err, val) { + if (err) { + console.error(`Failed to check the key 'startup'. Code:${err.code}, message:${err.message}`); + return; + } + if (val) { + console.info("The key 'startup' is contained."); + } else { + console.info("The key 'startup' does not contain."); + // 此处以此键值对不存在时写入数据为例 + try { + preferences.put('startup', 'auto', (err) => { + if (err) { + console.error(`Failed to put data. Code:${err.code}, message:${err.message}`); + return; + } + console.info('Succeeded in putting data.'); + }) + } catch (err) { + console.error(`Failed to put data. Code: ${err.code},message:${err.message}`); + } + } + }) + } catch (err) { + console.error(`Failed to check the key 'startup'. Code:${err.code}, message:${err.message}`); + } + ``` + +4. 读取数据。 + + 使用get()方法获取数据,即指定键对应的值。如果值为null或者非默认值类型,则返回默认数据。示例代码如下所示: + + ```js + try { + preferences.get('startup', 'default', (err, val) => { + if (err) { + console.error(`Failed to get value of 'startup'. Code:${err.code}, message:${err.message}`); + return; + } + console.info(`Succeeded in getting value of 'startup'. val: ${val}.`); + }) + } catch (err) { + console.error(`Failed to get value of 'startup'. Code:${err.code}, message:${err.message}`); + } + ``` + +5. 删除数据。 + + 使用delete()方法删除指定键值对,示例代码如下所示: + + + ```js + try { + preferences.delete('startup', (err) => { + if (err) { + console.error(`Failed to delete the key 'startup'. Code:${err.code}, message:${err.message}`); + return; + } + console.info("Succeeded in deleting the key 'startup'."); + }) + } catch (err) { + console.error(`Failed to delete the key 'startup'. Code:${err.code}, message:${err.message}`); + } + ``` + +6. 数据持久化。 + + 应用存入数据到Preferences实例后,可以使用flush()方法实现数据持久化。示例代码如下所示: + + ```js + try { + preferences.flush((err) => { + if (err) { + console.error(`Failed to flush. Code:${err.code}, message:${err.message}`); + return; + } + console.info('Succeeded in flushing.'); + }) + } catch (err) { + console.error(`Failed to flush. Code:${err.code}, message:${err.message}`); + } + ``` + +7. 订阅数据变更。 + + 应用订阅数据变更需要指定observer作为回调方法。订阅的Key值发生变更后,当执行flush()方法时,observer被触发回调。示例代码如下所示: + + ```js + let observer = function (key) { + console.info('The key' + key + 'changed.'); + } + preferences.on('change', observer); + // 数据产生变更,由'auto'变为'manual' + preferences.put('startup', 'manual', (err) => { + if (err) { + console.error(`Failed to put the value of 'startup'. Code:${err.code},message:${err.message}`); + return; + } + console.info("Succeeded in putting the value of 'startup'."); + preferences.flush((err) => { + if (err) { + console.error(`Failed to flush. Code:${err.code}, message:${err.message}`); + return; + } + console.info('Succeeded in flushing.'); + }) + }) + ``` + +8. 删除指定文件。 + + 使用deletePreferences()方法从内存中移除指定文件对应的Preferences实例,包括内存中的数据。若该Preference存在对应的持久化文件,则同时删除该持久化文件,包括指定文件及其备份文件、损坏文件。 + + > **说明:** + > + > - 调用该接口后,应用不允许再使用该Preferences实例进行数据操作,否则会出现数据一致性问题。 + > + > - 成功删除后,数据及文件将不可恢复。 + + 示例代码如下所示: + + + ```js + try { + dataPreferences.deletePreferences(this.context, 'mystore', (err, val) => { + if (err) { + console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`); + return; + } + console.info('Succeeded in deleting preferences.'); + }) + } catch (err) { + console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`); + } + ``` + +## 相关实例 + +针对用户首选项开发,有以下相关实例可供参考: + +- [`Preferences`:首选项(ArkTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-3.2-Release/data/Preferences) + +- [首选项(ArkTS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Data/Preferences) \ No newline at end of file diff --git a/zh-cn/application-dev/database/data-persistence-by-rdb-store.md b/zh-cn/application-dev/database/data-persistence-by-rdb-store.md new file mode 100644 index 0000000000000000000000000000000000000000..63eb604ba518f16cb37032642bd6ec4490c659e8 --- /dev/null +++ b/zh-cn/application-dev/database/data-persistence-by-rdb-store.md @@ -0,0 +1,237 @@ +# 通过关系型数据库实现数据持久化 + + +## 场景介绍 + +关系型数据库基于SQLite组件,适用于存储包含复杂关系数据的场景,比如一个班级的学生信息,需要包括姓名、学号、各科成绩等,又或者公司的雇员信息,需要包括姓名、工号、职位等,由于数据之间有较强的对应关系,复杂程度比键值型数据更高,此时需要使用关系型数据库来持久化保存数据。 + + +## 基本概念 + +- **谓词**:数据库中用来代表数据实体的性质、特征或者数据实体之间关系的词项,主要用来定义数据库的操作条件。 + +- **结果集**:指用户查询之后的结果集合,可以对数据进行访问。结果集提供了灵活的数据访问方式,可以更方便地拿到用户想要的数据。 + + +## 运作机制 + +关系型数据库对应用提供通用的操作接口,底层使用SQLite作为持久化存储引擎,支持SQLite具有的数据库特性,包括但不限于事务、索引、视图、触发器、外键、参数化查询和预编译SQL语句。 + +**图1** 关系型数据库运作机制 + +![relationStore_local](figures/relationStore_local.jpg) + + +## 约束限制 + +- 系统默认日志方式是WAL(Write Ahead Log)模式,系统默认落盘方式是FULL模式。 + +- 数据库中连接池的最大数量是4个,用以管理用户的读操作。 + +- 为保证数据的准确性,数据库同一时间只能支持一个写操作。 + +- 当应用被卸载完成后,设备上的相关数据库文件及临时文件会被自动清除。 + + +## 接口说明 + +以下是关系型数据库持久化功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见[关系型数据库](../reference/apis/js-apis-data-relationalStore.md)。 + +| 接口名称 | 描述 | +| -------- | -------- | +| getRdbStore(context: Context, config: StoreConfig, callback: AsyncCallback<RdbStore>): void | 获得一个相关的RdbStore,操作关系型数据库,用户可以根据自己的需求配置RdbStore的参数,然后通过RdbStore调用相关接口可以执行相关的数据操作。 | +| executeSql(sql: string, bindArgs: Array<ValueType>, callback: AsyncCallback<void>):void | 执行包含指定参数但不返回值的SQL语句。 | +| insert(table: string, values: ValuesBucket, callback: AsyncCallback<number>):void | 向目标表中插入一行数据。 | +| update(values: ValuesBucket, predicates: RdbPredicates, callback: AsyncCallback<number>):void | 根据RdbPredicates的指定实例对象更新数据库中的数据。 | +| delete(predicates: RdbPredicates, callback: AsyncCallback<number>):void | 根据RdbPredicates的指定实例对象从数据库中删除数据。 | +| query(predicates: RdbPredicates, columns: Array<string>, callback: AsyncCallback<ResultSet>):void | 根据指定条件查询数据库中的数据。 | +| deleteRdbStore(context: Context, name: string, callback: AsyncCallback<void>): void | 删除数据库。 | + + +## 开发指导 + +1. 使用关系型数据库实现数据持久化,需要获取一个RdbStore。示例代码如下所示: + + Stage模型示例: + + ```js + import relationalStore from '@ohos.data.relationalStore'; // 导入模块 + import UIAbility from '@ohos.app.ability.UIAbility'; + + class EntryAbility extends UIAbility { + onWindowStageCreate(windowStage) { + const STORE_CONFIG = { + name: 'RdbTest.db', // 数据库文件名 + securityLevel: relationalStore.SecurityLevel.S1 // 数据库安全级别 + }; + + 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语句 + + 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.`); + store.executeSql(SQL_CREATE_TABLE); // 创建数据表 + + // 这里执行数据库的增、删、改、查等操作 + + }); + } + } + ``` + + FA模型示例: + + + ```js + import relationalStore from '@ohos.data.relationalStore'; // 导入模块 + import featureAbility from '@ohos.ability.featureAbility'; + + // 获取context + let context = featureAbility.getContext(); + + const STORE_CONFIG = { + name: 'RdbTest.db', // 数据库文件名 + securityLevel: relationalStore.SecurityLevel.S1 // 数据库安全级别 + }; + + 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语句 + + 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.`); + store.executeSql(SQL_CREATE_TABLE); // 创建数据表 + + // 这里执行数据库的增、删、改、查等操作 + + }); + ``` + + > **说明:** + > + > - 应用创建的数据库与其上下文(Context)有关,即使使用同样的数据库名称,但不同的应用上下文,会产生多个数据库,例如每个UIAbility都有各自的上下文。 + > + > - 当应用首次获取数据库(调用getRdbStore)后,在应用沙箱内会产生对应的数据库文件。使用数据库的过程中,数据库文件相同的目录下,可以会产生以-wal和-shm结尾的临时文件,此时开发者希望移到数据库文件到其它地方使用可查看,需要同时移动这些临时文件。当应用被卸载完成后,其在设备上产生的数据库文件及临时文件也会被移除。 + +2. 获取到RdbStore后,调用insert()接口插入数据。示例代码如下所示: + + ```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}`); + }) + ``` + + > **说明:** + > + > 关系型数据库没有显式的flush操作实现持久化,数据插入即保存在持久化文件。 + +3. 根据谓词指定的实例对象,对数据进行修改或删除。 + + 调用update()方法修改数据,调用delete()方法删除数据。示例代码如下所示: + + ```js + // 修改数据 + const valueBucket = { + 'NAME': 'Rose', + 'AGE': 22, + 'SALARY': 200.5, + 'CODES': new Uint8Array([1, 2, 3, 4, 5]) + }; + let predicates = new relationalStore.RdbPredicates('EMPLOYEE'); // 创建表'EMPLOYEE'的predicates + predicates.equalTo('NAME', 'Lisa'); // 匹配表'EMPLOYEE'中'NAME'为'Lisa'的字段 + 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}`); + }) + + // 删除数据 + 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()方法查找数据,返回一个ResultSet结果集。示例代码如下所示: + + ```js + let predicates = new relationalStore.RdbPredicates('EMPLOYEE'); + predicates.equalTo('NAME', 'Rose'); + store.query(predicates, ['ID', 'NAME', 'AGE', 'SALARY', 'CODES'], (err, resultSet) => { + if (err) { + console.error(`Failed to query data. Code:${err.code}, message:${err.message}`); + return; + } + console.info(`ResultSet column names: ${resultSet.columnNames}`); + console.info(`ResultSet column count: ${resultSet.columnCount}`); + }) + ``` + + > **说明:** + > + > 当应用完成查询数据操作,不再使用结果集(ResultSet)时,请及时调用close方法关闭结果集,释放系统为其分配的内存。 + +5. 删除数据库。 + + 调用deleteRdbStore()方法,删除数据库及数据库相关文件。示例代码如下: + + Stage模型示例: + + + ```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; + } + console.info('Succeeded in deleting RdbStore.'); + }); + } + } + ``` + + FA模型示例: + + + ```js + import featureAbility from '@ohos.ability.featureAbility'; + + // 获取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; + } + console.info('Succeeded in deleting RdbStore.'); + }); + ``` diff --git a/zh-cn/application-dev/database/data-reliability-security-overview.md b/zh-cn/application-dev/database/data-reliability-security-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..526503039bd31dc49da7448f62f7a2f2e14540ed --- /dev/null +++ b/zh-cn/application-dev/database/data-reliability-security-overview.md @@ -0,0 +1,64 @@ +# 数据可靠性与安全性概述 + +## 功能场景 + +在系统运行中,存储损坏、存储空间不足、文件系统权限、系统掉电等都可能导致数据库发生故障。比如联系人应用的数据库损坏,导致用户的联系人丢失;日历应用的数据库损坏,导致丢失日历提醒等。为此数据管理提供了数据可靠性与安全性相关的解决方案和能力保障。 + +- 备份、恢复功能:重要业务应用(如银行)数据丢失,出现严重异常场景,可以通过备份恢复数据库,保证关键数据不丢失。 + +- 数据库加密功能:当数据库中存储如认证凭据、财务数据等高敏感信息时,可对数据库进行加密,提高数据库安全性。 + +- 数据库分类分级:数据跨设备同步时,数据管理基于数据安全标签和设备安全等级进行访问控制,保证数据安全。 + +另外,备份数据库存储在应用的沙箱内,当存储空间不足时,可以选择删除本地的数据库备份,释放空间。 + + +## 基本概念 + +在进行数据可靠性与安全性相关功能的开发前,请先了解以下相关概念。 + + +### 数据库备份与恢复 + +- **数据库备份**:指对当前数据库的数据库文件进行完整备份。OpenHarmony数据库备份针对数据库全量文件进行完整的备份。 + 在进行数据库备份的时候,无需关闭数据库,直接调用对应的数据库备份接口就能完成对数据库文件的备份。 + +- **数据库恢复**:从指定的备份文件恢复到当前数据库文件。恢复完成时,当前数据库数据恢复到和指定备份文件一致。 + + +### 数据库加密 + +数据库加密是对整个数据库文件的加密,可以增强数据库的安全性,有效保护数据库内容。 + + +### 数据库分类分级 + +分布式数据管理对数据实施分类分级保护,提供基于数据安全标签以及设备安全等级的访问控制机制。 + +数据安全标签和设备安全等级越高,加密措施和访问控制措施越严格,数据安全性越高。 + + +## 运作机制 + + +### 数据库备份与恢复机制 + +数据库在备份时,会将当前的数据库备份在指定的文件中,后续对数据库的操作不会影响备份的数据库文件。只有当恢复指定数据库文件时,才会将备份的数据库文件覆盖当前数据库,实现数据的回滚。 + +- 键值型数据库备份路径:/data/service/el1(el2)/public/database/...{appId}/kvdb/backup/...{storeId} + +- 关系型数据库备份路径:/data/app/el1(el2)/100/database/...{bundlename}/rdb + + +### 数据库加密机制 + +OpenHarmony数据库加密时,应用开发者无需传入密钥,只需要设置数据库加密的状态即可。系统会自动帮助开发者将数据库加密,使用[huks通用密钥库系统](../reference/apis/js-apis-huks.md),完成数据库密钥的生成及加密保护。 + + +## 约束限制 + +- 数据库加密的密钥一年自动更换一次。 + +- 键值型数据库最多可以备份5份。 + +- 键值型数据库的自动备份需要在熄屏且充电的状态下进行。 diff --git a/zh-cn/application-dev/database/data-sync-of-distributed-data-object.md b/zh-cn/application-dev/database/data-sync-of-distributed-data-object.md new file mode 100644 index 0000000000000000000000000000000000000000..04989e84044d89f1de46f64e10cb79d13a550f05 --- /dev/null +++ b/zh-cn/application-dev/database/data-sync-of-distributed-data-object.md @@ -0,0 +1,315 @@ +# 分布式数据对象跨设备数据同步 + + +## 场景介绍 + +传统方式下,设备之间的数据同步,需要开发者完成消息处理逻辑,包括:建立通信链接、消息收发处理、错误重试、数据冲突解决等操作,工作量非常大。而且设备越多,调试复杂度也将同步增加。 + +其实设备之间的状态、消息发送进度、发送的数据等都是“变量”。如果这些变量支持“全局”访问,那么开发者跨设备访问这些变量就能像操作本地变量一样,从而能够自动高效、便捷地实现数据多端同步。 + +分布式数据对象即实现了对“变量”的“全局”访问。向应用开发者提供内存对象的创建、查询、删除、修改、订阅等基本数据对象的管理能力,同时具备分布式能力。为开发者在分布式应用场景下提供简单易用的JS接口,轻松实现多设备间同应用的数据协同,同时设备间可以监听对象的状态和数据变更。满足超级终端场景下,相同应用多设备间的数据对象协同需求。与传统方式相比,分布式数据对象大大减少了开发者的工作量。 + + +## 基本概念 + +- **分布式内存数据库** + 分布式内存数据库将数据缓存在内存中,以便应用获得更快的数据存取速度,不会将数据进行持久化。若数据库关闭,则数据不会保留。 + +- **分布式数据对象** + 分布式数据对象是一个JS对象型的封装。每一个分布式数据对象实例会创建一个内存数据库中的数据表,每个应用程序创建的内存数据库相互隔离,对分布式数据对象的“读取”或“赋值”会自动映射到对应数据库的get/put操作。 + + 分布式数据对象的生命周期包括以下状态: + + - 未初始化:未实例化,或已被销毁。 + - 本地数据对象:已创建对应的数据表,但是还无法进行数据同步。 + - 分布式数据对象:已创建对应的数据表,设备在线且组网内设置同样sessionId的对象数>=2,可以跨设备同步数据。若设备掉线或将sessionId置为空,分布式数据对象退化为本地数据对象。 + + +## 运作机制 + + **图1** 分布式数据对象运作机制  +   +![distributedObject](figures/distributedObject.jpg) + +分布式数据对象生长在分布式内存数据库之上,在分布式内存数据库上进行了JS对象型的封装,能像操作本地变量一样操作分布式数据对象,数据的跨设备同步由系统自动完成。 + + +### JS对象型存储与封装机制 + +- 为每个分布式数据对象实例创建一个内存数据库,通过SessionId标识,每个应用程序创建的内存数据库相互隔离。 + +- 在分布式数据对象实例化的时候,(递归)遍历对象所有属性,使用“Object.defineProperty”定义所有属性的set和get方法,set和get中分别对应数据库一条记录的put和get操作,Key对应属性名,Value对应属性值。 + +- 在开发者对分布式数据对象进行“读取”或者“赋值”的时候,都会自动调用到set和get方法,映射到对应数据库的操作。 + +**表1** 分布式数据对象和分布式数据库的对应关系 + +| 分布式对象实例 | 对象实例 | 属性名称 | 属性值 | +| -------- | -------- | -------- | -------- | +| 分布式内存数据库 | 一个数据库(sessionID标识) | 一条数据库记录的key | 一条数据库记录的value | + + +### 跨设备同步和数据变更通知机制 + +分布式数据对象,最重要的功能就是对象之间的数据同步。可信组网内的设备可以在本地创建分布式数据对象,并设置sessionID。不同设备上的分布式数据对象,通过设置相同的sessionID,建立对象之间的同步关系。 + +如下图所示,设备A和设备B上的“分布式数据对象1”,其sessionID均为session1,这两个对象建立了session1的同步关系。 + + **图2** 对象的同步关系   + +![distributedObject_sync](figures/distributedObject_sync.jpg) + +一个同步关系中,一个设备只能有一个对象加入。比如上图中,设备A的“分布式数据对象1”已经加入了session1的同步关系,所以设备A的“分布式数据对象2”就加入失败了。 + +建立同步关系后,每个Session有一份共享对象数据。加入了同一个Session的对象,支持以下操作: + +(1)读取/修改Session中的数据。 + +(2)监听数据变更,感知其他设备对共享对象数据的修改。 + +(3)监听状态变更,感知其他设备的加入和退出。 + + +### 同步的最小单位 + +关于分布式数据对象的数据同步,值得注意的是,同步的最小单位是“属性”。比如,下图中对象1包含三个属性:name、age和parents。当其中一个属性变更时,则数据同步时只需同步此变更的属性。 + +**图3** 数据同步视图  + + +![distributedObject_syncView](figures/distributedObject_syncView.jpg) + + +### 对象持久化缓存机制 + +分布式对象主要运行在应用程序的进程空间。当调用分布式对象持久化接口时,通过分布式数据库对对象进行持久化和同步,进程退出后数据也不会丢失。 + +该场景是分布式对象的扩展场景,主要用于以下情况: + +- 在设备上创建持久化对象后APP退出,重新打开APP,创建持久化对象,加入同一个Session,数据可以恢复到APP退出前的数据。 + +- 在设备A上创建持久化对象并同步后持久化到设备B后,A设备的APP退出,设备B打开APP,创建持久化对象,加入同一个Session,数据可以恢复到A设备退出前的数据。 + + +## 约束限制 + +- 不同设备间只有相同bundleName的应用才能直接同步。 + +- 分布式数据对象的数据同步发生在同一个应用程序下,且同sessionID之间。 + +- 不建议创建过多的分布式数据对象,每个分布式数据对象将占用100-150KB内存。 + +- 每个分布式数据对象大小不超过500KB。 + +- 设备A修改1KB数据,设备B收到变更通知,50ms内完成。 + +- 单个应用程序最多只能创建16个分布式数据对象实例。 + +- 考虑到性能和用户体验,最多不超过3个设备进行数据协同。 + +- 如对复杂类型的数据进行修改,仅支持修改根属性,暂不支持下级属性修改。 + +- 支持JS接口间的互通,与其他语言不互通。 + + +## 接口说明 + +以下是分布式对象跨设备数据同步功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见[分布式数据对象](reference/apis/js-apis-data-distributedobject.md)。 + +| 接口名称 | 描述 | +| -------- | -------- | +| create(context: Context, source: object): DataObject | 创建并得到一个分布式数据对象实例。 | +| genSessionId(): string | 创建一个sessionId,可作为分布式数据对象的sessionId。 | +| setSessionId(sessionId: string, callback: AsyncCallback<void>): void | 设置同步的sessionId,当可信组网中有多个设备时,多个设备间的对象如果设置为同一个sessionId,就能自动同步。 | +| setSessionId(callback: AsyncCallback<void>): void | 退出所有已加入的session。 | +| on(type: 'change', callback: Callback<{ sessionId: string, fields: Array<string> }>): void | 监听分布式数据对象的数据变更。 | +| on(type: 'status', callback: Callback<{ sessionId: string, networkId: string, status: 'online' \| 'offline' }>): void | 监听分布式数据对象的上下线。 | +| save(deviceId: string, callback: AsyncCallback<SaveSuccessResponse>): void | 保存分布式数据对象。 | +| revokeSave(callback: AsyncCallback<RevokeSaveSuccessResponse>): void | 撤回保存的分布式数据对象。 | + + +## 开发步骤 + +以一次分布式数据对象同步为例,说明开发步骤。 + +1. 导入`@ohos.data.distributedDataObject`模块。 + + ```js + import distributedDataObject from '@ohos.data.distributedDataObject'; + ``` + +2. 请求权限。 + + 1. 需要申请ohos.permission.DISTRIBUTED_DATASYNC权限,配置方式请参见[配置文件权限声明](../security/accesstoken-guidelines.md#配置文件权限声明)。 + 2. 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见[向用户申请授权](../security/accesstoken-guidelines.md#向用户申请授权)。 + +3. 创建并得到一个分布式数据对象实例。 + + Stage模型示例: + + ```js + // 导入模块 + import distributedDataObject from '@ohos.data.distributedDataObject'; + import UIAbility from '@ohos.app.ability.UIAbility'; + + class EntryAbility extends UIAbility { + onWindowStageCreate(windowStage) { + // 创建对象,该对象包含4个属性类型:string、number、boolean和Object + let localObject = distributedDataObject.create(this.context, { + name: 'jack', + age: 18, + isVis: false, + parent: { mother: 'jack mom', father: 'jack Dad' }, + list: [{ mother: 'jack mom' }, { father: 'jack Dad' }] + }); + } + } + ``` + + FA模型示例: + + + ```js + // 导入模块 + import distributedDataObject from '@ohos.data.distributedDataObject'; + import featureAbility from '@ohos.ability.featureAbility'; + // 获取context + let context = featureAbility.getContext(); + // 创建对象,该对象包含4个属性类型:string、number、boolean和Object + let localObject = distributedDataObject.create(context, { + name: 'jack', + age: 18, + isVis: false, + parent: { mother: 'jack mom', father: 'jack Dad' }, + list: [{ mother: 'jack mom' }, { father: 'jack Dad' }] + }); + ``` + +4. 加入同步组网。同步组网中的数据对象分为发起方和被拉起方。 + + ```js + // 设备1加入sessionId + let sessionId = '123456'; + + localObject.setSessionId(sessionId); + + // 和设备1协同的设备2加入同一个session + + // 创建对象,该对象包含4个属性类型:string、number、boolean和Object + let remoteObject = distributedDataObject.create(this.context, { + name: undefined, + age: undefined, // undefined表示数据来自对端 + isVis: true, + parent: undefined, + list: undefined + }); + // 收到status上线后remoteObject同步数据,即name变成jack,age是18 + remoteObject.setSessionId(sessionId); + ``` + +5. 监听对象数据变更。可监听对端数据的变更,以callback作为变更回调实例。 + + ```js + function changeCallback(sessionId, changeData) { + console.info(`change: ${sessionId}`); + + if (changeData !== null && changeData !== undefined) { + changeData.forEach(element => { + console.info(`The element ${localObject[element]} changed.`); + }); + } + } + + // 发起方要在changeCallback里刷新界面,则需要将正确的this绑定给changeCallback + localObject.on("change", this.changeCallback.bind(this)); + ``` + +6. 修改对象属性,对象属性支持基本类型(数字类型、布尔类型、字符串类型)以及复杂类型(数组、基本类型嵌套等)。 + + ```js + localObject.name = 'jack1'; + localObject.age = 19; + localObject.isVis = false; + localObject.parent = { mother: 'jack1 mom', father: 'jack1 Dad' }; + localObject.list = [{ mother: 'jack1 mom' }, { father: 'jack1 Dad' }]; + ``` + + > **说明:** + > + > 针对复杂类型的数据修改,目前仅支持对根属性的修改,暂不支持对下级属性的修改。 + + + ```js + // 支持的修改方式 + localObject.parent = { mother: 'mom', father: 'dad' }; + // 不支持的修改方式 + localObject.parent.mother = 'mom'; + ``` + +7. 访问对象。可以通过直接获取的方式访问到分布式数据对象的属性,且该数据为组网内的最新数据。 + + ```js + console.info(`name:${localObject['name']}`); + ``` + +8. 删除监听数据变更。可以指定删除监听的数据变更回调;也可以不指定,这将会删除该分布式数据对象的所有数据变更回调。 + + ```js + // 删除变更回调changeCallback + localObject.off('change', this.changeCallback); + // 删除所有的变更回调 + localObject.off('change'); + ``` + +9. 监听分布式数据对象的上下线。可以监听对端分布式数据对象的上下线。 + + ```js + function statusCallback(sessionId, networkId, status) { + // 业务处理 + } + + localObject.on('status', this.statusCallback); + ``` + +10. 保存和撤回已保存的数据对象。 + + ```js + // 保存数据对象,如果应用退出后组网内设备需要恢复对象数据时调用 + localObject.save('local').then((result) => { + console.info(`Succeeded in saving. SessionId:${result.sessionId},version:${result.version},deviceId:${result.deviceId}`); + }).catch((err) => { + console.error(`Failed to save. Code:${err.code},message:${err.message}`); + }); + + // 撤回保存的数据对象 + localObject.revokeSave().then((result) => { + console.info(`Succeeded in revokeSaving. Session:${result.sessionId}`); + }).catch((err) => { + console.error(`Failed to revokeSave. Code:${err.code},message:${err.message}`); + }); + ``` + +11. 删除监听分布式数据对象的上下线。可以指定删除监听的上下线回调;也可以不指定,这将会删除该分布式数据对象的所有上下线回调。 + + ```js + // 删除上下线回调statusCallback + localObject.off('status', this.statusCallback); + // 删除所有的上下线回调 + localObject.off('status'); + ``` + +12. 退出同步组网。分布式数据对象退出组网后,本地的数据变更对端不会同步。 + + ```js + localObject.setSessionId(() => { + console.info('leave all lession.'); + }); + ``` + +## 相关实例 + +针对分布式数据对象,有以下相关实例可供参考: + +- [`DistributedNote`:分布式备忘录(ArkTS)(API9)(Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-3.2-Release/data/DistributedNote) + +- [`DistributedObjectDms`:分布式跑马灯(ArkTS)(API9)(Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-3.2-Release/data/DistributedObjectDms) \ No newline at end of file diff --git a/zh-cn/application-dev/database/data-sync-of-kv-store.md b/zh-cn/application-dev/database/data-sync-of-kv-store.md new file mode 100644 index 0000000000000000000000000000000000000000..fba04ef73477f296401ff0fc30a57bb63d5bec81 --- /dev/null +++ b/zh-cn/application-dev/database/data-sync-of-kv-store.md @@ -0,0 +1,277 @@ +# 键值型数据库跨设备数据同步 + + +## 场景介绍 + +键值型数据库适合不涉及过多数据关系和业务关系的业务数据存储,比SQL数据库存储拥有更好的读写性能,同时因其在分布式场景中降低了解决数据库版本兼容问题的复杂度,和数据同步过程中冲突解决的复杂度而被广泛使用。 + + +## 基本概念 + +在使用键值型数据库跨设备数据同步前,请先了解以下概念。 + + +### 单版本数据库 + +单版本是指数据在本地是以单个条目为单位的方式保存,当数据在本地被用户修改时,不管它是否已经被同步出去,均直接在这个条目上进行修改。多个设备全局只保留一份数据,多个设备的相同记录(主码相同)会按时间最新保留一条记录,数据不分设备,设备之间修改相同的key会覆盖。同步也以此为基础,按照它在本地被写入或更改的顺序将当前最新一次修改逐条同步至远端设备,常用于联系人、天气等应用存储场景。 + +![singleKVStore](figures/singleKVStore.jpg) + + +### 多设备协同数据库 + +多设备协同分布式数据库建立在单版本数据库之上,对应用程序存入的键值型数据中的Key前面拼接了本设备的DeviceID标识符,这样能保证每个设备产生的数据严格隔离。数据以设备的维度管理,不存在冲突;支持按照设备的维度查询数据。 + +底层按照设备的维度管理这些数据,多设备协同数据库支持以设备的维度查询分布式数据,但是不支持修改远端设备同步过来的数据。需要分开查询各设备数据的可以使用设备协同版本数据库。常用于图库缩略图存储场景。 + +![deviceKVStore](figures/deviceKVStore.jpg) + + +## 同步方式 + +数据管理服务提供了两种同步方式:手动同步和自动同步。键值型数据库可选择其中一种方式实现同应用跨设备数据同步。 + + +- **手动同步**:由应用程序调用sync接口来触发,需要指定同步的设备列表和同步模式。同步模式分为PULL_ONLY(将远端数据拉取到本端)、PUSH_ONLY(将本端数据推送到远端)和PUSH_PULL(将本端数据推送到远端同时也将远端数据拉取到本端)。[带有Query参数的同步接口](../reference/apis/js-apis-distributedKVStore.md#sync-1),支持按条件过滤的方法进行同步,将符合条件的数据同步到远端。手动同步功能,仅系统应用可用。 + +- **自动同步**:由分布式数据库自动将本端数据推送到远端,同时也将远端数据拉取到本端来完成数据同步,同步时机包括设备上线、应用程序更新数据等,应用不需要主动调用sync接口。 + + +## 运作机制 + +底层通信组件完成设备发现和认证,会通知上层应用程序设备上线。收到设备上线的消息后数据管理服务可以在两个设备之间建立加密的数据传输通道,利用该通道在两个设备之间进行数据同步。 + + +### 数据跨设备同步机制 + +![kvStore](figures/kvStore.jpg) + +如图所示,通过put、delete接口触发自动同步,将分布式数据通过通信适配层发送给对端设备,实现分布式数据的自动同步; + +手动同步则是手动调用sync接口触发同步,将分布式数据通过通信适配层发送给对端设备。 + + +### 数据变化通知机制 + +增、删、改数据库时,会给订阅者发送数据变化的通知。主要分为本地数据变化通知和分布式数据变化通知。 + +- **本地数据变化通知**:本地设备的应用内订阅数据变化通知,数据库增删改数据时,会收到通知。 + +- **分布式数据变化通知**:同一应用订阅组网内其他设备数据变化的通知,其他设备增删改数据时,本设备会收到通知。数据变化通知可以让用户及时感知到两端数据的不同,并进行同步操作,保证分布式数据库的一致性。 + + +## 约束限制 + +- 设备协同数据库,针对每条记录,Key的长度≤896 Byte,Value的长度<4 MB。 + +- 单版本数据库,针对每条记录,Key的长度≤1 KB,Value的长度<4 MB。 + +- 键值型数据库不支持应用程序自定义冲突解决策略。 + +- 每个应用程序最多支持同时打开16个分布式数据库。 + +- 允许同时订阅数据变化通知的数据库最大数量为8个。 + +- 手动同步功能,仅系统应用可用。 + + +## 接口说明 + +以下是单版本键值型分布式数据库跨设备数据同步功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见[分布式键值数据库](../reference/apis/js-apis-distributedKVStore.md)。 + +| 接口名称 | 描述 | +| -------- | -------- | +| createKVManager(config: KVManagerConfig): KVManager | 创建一个KVManager对象实例,用于管理数据库对象。 | +| getKVStore<T>(storeId: string, options: Options, callback: AsyncCallback<T>): void | 指定Options和storeId,创建并得到指定类型的KVStore数据库。 | +| put(key: string, value: Uint8Array\|string\|number\|boolean, callback: AsyncCallback<void>): void | 插入和更新数据。 | +| on(event: 'dataChange', type: SubscribeType, listener: Callback<ChangeNotification>): void | 订阅数据库中数据的变化。 | +| get(key: string, callback: AsyncCallback<boolean \| string \| number \| Uint8Array>): void | 查询指定Key键的值。 | +| sync(deviceIds: string[], mode: SyncMode, delayMs?: number): void | 在手动模式下,触发数据库同步。 | + + +## 开发步骤 + +此处以单版本键值型数据库跨设备数据同步的开发为例。以下是具体的开发流程和开发步骤。 + +![kvStore_development_process](figures/kvStore_development_process.png) + +> **说明:** +> +> 数据只允许向数据安全标签不高于对端设备安全等级的设备同步数据,具体规则可见[跨设备同步访问控制机制](sync-app-data-across-devices-overview.md#跨设备同步访问控制机制)。 + +1. 导入模块。 + + ```js + import distributedKVStore from '@ohos.data.distributedKVStore'; + ``` + +2. 请求权限。 + + 1. 需要申请ohos.permission.DISTRIBUTED_DATASYNC权限,配置方式请参见[配置文件权限声明](../security/accesstoken-guidelines.md#配置文件权限声明)。 + 2. 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见[向用户申请授权](../security/accesstoken-guidelines.md#向用户申请授权)。 + +3. 根据配置构造分布式数据库管理类实例。 + + 1. 根据应用上下文创建kvManagerConfig对象。 + 2. 创建分布式数据库管理器实例。 + + + ```js + // Stage模型获取context + import UIAbility from '@ohos.app.ability.UIAbility'; + let kvManager; + let context = null; + + class EntryAbility extends UIAbility { + onWindowStageCreate(windowStage) { + context = this.context; + } + } + + // FA模型获取context + import featureAbility from '@ohos.ability.featureAbility'; + + let context = featureAbility.getContext(); + + // 获取context之后,构造分布式数据库管理类实例 + try { + const kvManagerConfig = { + bundleName: 'com.example.datamanagertest', + context: context + } + kvManager = distributedKVStore.createKVManager(kvManagerConfig); + console.info('Succeeded in creating KVManager.'); + // 继续创建获取数据库 + } catch (e) { + console.error(`Failed to create KVManager. Code:${e.code},message:${e.message}`); + } + ``` + +4. 获取并得到指定类型的键值型数据库。 + + 1. 声明需要创建的分布式数据库ID描述。 + 2. 创建分布式数据库,建议关闭自动同步功能(autoSync:false),方便后续对同步功能进行验证,需要同步时主动调用sync接口。 + + + ```js + try { + const options = { + createIfMissing: true, + encrypt: false, + backup: false, + autoSync: false, + kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, + // 设备协同数据库:kvStoreType: distributedKVStore.KVStoreType.DEVICE_COLLABORATION, + securityLevel: distributedKVStore.SecurityLevel.S1 + }; + kvManager.getKVStore('storeId', options, (err, kvStore) => { + if (err) { + console.error(`Failed to get KVStore: Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in getting KVStore.'); + // 进行相关数据操作 + }); + } catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); + } + ``` + +5. 订阅分布式数据变化。 + + ```js + try { + kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, (data) => { + console.info(`dataChange callback call data: ${data}`); + }); + } catch (e) { + console.error(`An unexpected error occured. code:${e.code},message:${e.message}`); + } + ``` + +6. 将数据写入分布式数据库。 + + 1. 构造需要写入分布式数据库的Key(键)和Value(值)。 + 2. 将键值数据写入分布式数据库。 + + + ```js + const KEY_TEST_STRING_ELEMENT = 'key_test_string'; + const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; + try { + kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => { + if (err !== undefined) { + console.error(`Failed to put data. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in putting data.'); + }); + } catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); + } + ``` + +7. 查询分布式数据库数据。 + + 1. 构造需要从单版本分布式数据库中查询的Key(键)。 + 2. 从单版本分布式数据库中获取数据。 + + + ```js + const KEY_TEST_STRING_ELEMENT = 'key_test_string'; + const VALUE_TEST_STRING_ELEMENT = 'value_test_string'; + try { + kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => { + if (err !== undefined) { + console.error(`Failed to put data. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in putting data.'); + kvStore.get(KEY_TEST_STRING_ELEMENT, (err, data) => { + if (err != undefined) { + console.error(`Failed to get data. Code:${err.code},message:${err.message}`); + return; + } + console.info(`Succeeded in getting data. Data:${data}`); + }); + }); + } catch (e) { + console.error(`Failed to get data. Code:${e.code},message:${e.message}`); + } + ``` + +8. 同步数据到其他设备。 + + 选择同一组网环境下的设备以及同步模式(需用户在应用首次启动的弹窗中确认选择同步模式),进行数据同步。 + + > **说明:** + > + > 在手动同步的方式下,其中的deviceIds通过调用[devManager.getTrustedDeviceListSync](../reference/apis/js-apis-device-manager.md#gettrusteddevicelistsync)方法得到,deviceManager模块的接口均为系统接口,仅系统应用可用。 + + + ```js + import deviceManager from '@ohos.distributedHardware.deviceManager'; + + let devManager; + // create deviceManager + deviceManager.createDeviceManager('bundleName', (err, value) => { + if (!err) { + devManager = value; + // deviceIds由deviceManager调用getTrustedDeviceListSync方法得到 + let deviceIds = []; + if (devManager !== null) { + //需要权限:ohos.permission.ACCESS_SERVICE_DM,仅系统应用可以获取 + let devices = devManager.getTrustedDeviceListSync(); + for (let i = 0; i < devices.length; i++) { + deviceIds[i] = devices[i].deviceId; + } + } + try { + // 1000表示最大延迟时间为1000ms + kvStore.sync(deviceIds, distributedKVStore.SyncMode.PUSH_ONLY, 1000); + } catch (e) { + console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`); + } + } + }); + ``` diff --git a/zh-cn/application-dev/database/data-sync-of-rdb-store.md b/zh-cn/application-dev/database/data-sync-of-rdb-store.md new file mode 100644 index 0000000000000000000000000000000000000000..dea62a60dab0f7a803410af54a61ec288241fd1d --- /dev/null +++ b/zh-cn/application-dev/database/data-sync-of-rdb-store.md @@ -0,0 +1,173 @@ +# 关系型数据库跨设备数据同步 + + +## 场景介绍 + +当应用程序本地存储的关系型数据存在跨设备同步的需求时,可以将需求同步的表数据迁移到新的支持跨设备的表中,当然也可以在刚完成表创建时设置其支持跨设备。 + + +## 基本概念 + +关系型数据库跨设备数据同步,支持应用在多设备间同步存储的关系型数据。 + +- 分布式列表,应用在数据库中新创建表后,可以设置其为分布式表。在查询远程设备数据库时,根据本地表名可以获取指定远程设备的分布式表名。 + +- 设备之间同步数据,数据同步有两种方式,将数据从本地设备推送到远程设备或将数据从远程设备拉至本地设备。 + + +## 运作机制 + +底层通信组件完成设备发现和认证,会通知上层应用程序设备上线。收到设备上线的消息后数据管理服务可以在两个设备之间建立加密的数据传输通道,利用该通道在两个设备之间进行数据同步。 + + +### 数据跨设备同步机制 + +![relationalStore_sync](figures/relationalStore_sync.jpg) + +业务将数据写入关系型数据库或键值型数据库后,向数据管理服务发起同步请求。 + +数据管理服务从应用沙箱内读取待同步数据,根据对端设备的deviceId将数据发送到其他设备的数据管理服务。再由数据管理服务将数据写入同应用的数据库内。 + + +### 数据变化通知机制 + +增、删、改数据库时,会给订阅者发送数据变化的通知。主要分为本地数据变化通知和分布式数据变化通知。 + +- **本地数据变化通知**:本地设备的应用内订阅数据变化通知,数据库增删改数据时,会收到通知。 + +- **分布式数据变化通知**:同一应用订阅组网内其他设备数据变化的通知,其他设备增删改数据时,本设备会收到通知。数据变化通知可以让用户及时感知到两端数据的不同,并进行同步操作,保证分布式数据库的一致性。 + + +## 约束限制 + +- 每个应用程序最多支持同时打开16个分布式数据库。 + +- 允许同时订阅数据变化通知的数据库最大数量为8个。 + +- 不支持非系统应用调用需要指定设备的分布式能力接口。 + + +## 接口说明 + +以下是关系型设备协同分布式数据库跨设备数据同步功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见[关系型数据库](../reference/apis/js-apis-data-relationalStore.md)。 + +| 接口名称 | 描述 | +| -------- | -------- | +| setDistributedTables(tables: Array<string>, callback: AsyncCallback<void>): void | 设置分布式同步表。 | +| sync(mode: SyncMode, predicates: RdbPredicates, callback: AsyncCallback<Array<[string, number]>>): void | 分布式数据同步。 | +| on(event: 'dataChange', type: SubscribeType, observer: Callback<Array<string>>): void | 订阅分布式数据变化。 | +| off(event:'dataChange', type: SubscribeType, observer: Callback<Array<string>>): void | 取消订阅分布式数据变化。 | +| obtainDistributedTableName(device: string, table: string, callback: AsyncCallback<string>): void; | 根据本地数据库表名获取指定设备上的表名。 | +| remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array<string> , callback: AsyncCallback<ResultSet>): void | 根据指定条件查询远程设备数据库中的数据。 | + + +## 开发步骤 + +> **说明:** +> +> 数据只允许向数据安全标签不高于对端设备安全等级的设备同步数据,具体规则可见[跨设备同步访问控制机制](sync-app-data-across-devices-overview.md#跨设备同步访问控制机制)。 + +1. 导入模块。 + + ```js + import relationalStore from '@ohos.data.relationalStore'; + ``` + +2. 请求权限。 + + 1. 需要申请ohos.permission.DISTRIBUTED_DATASYNC权限,配置方式请参见[配置文件权限声明](../security/accesstoken-guidelines.md#配置文件权限声明)。 + 2. 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见[向用户申请授权](../security/accesstoken-guidelines.md#向用户申请授权)。 + +3. 创建关系型数据库,设置将需要进行分布式同步的表。 + + ```js + const STORE_CONFIG = { + name: 'RdbTest.db', // 数据库文件名 + securityLevel: relationalStore.SecurityLevel.S1 // 数据库安全级别 + }; + relationalStore.getRdbStore(this.context, STORE_CONFIG, (err, store) => { + store.executeSql('CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, AGE INTEGER, SALARY REAL, CODES BLOB)', null, (err) => { + // 设置分布式同步表。 + store.setDistributedTables(['EMPLOYEE']); + // 进行数据的相关操作 + }) + }) + ``` + +4. 分布式数据同步。使用SYNC_MODE_PUSH触发同步后,数据将从本设备向组网内的其它所有设备同步。 + + ```js + // 构造用于同步分布式表的谓词对象 + let predicates = new relationalStore.RdbPredicates('EMPLOYEE'); + // 调用同步数据的接口 + store.sync(relationalStore.SyncMode.SYNC_MODE_PUSH, predicates, (err, result) => { + // 判断数据同步是否成功 + if (err) { + console.error(`Failed to sync data. Code:${err.code},message:${err.message}`); + return; + } + console.info('Succeeded in syncing data.'); + for (let i = 0; i < result.length; i++) { + console.info(`device:${result[i][0]},status:${result[i][1]}`); + } + }) + ``` + +5. 分布式数据订阅。数据同步变化将触发订阅回调方法执行,回调方法的入参为发生变化的设备ID。 + + ```js + let observer = function storeObserver(devices) { + for (let i = 0; i < devices.length; i++) { + console.info(`The data of device:${devices[i]} has been changed.`); + } + } + + try { + // 调用分布式数据订阅接口,注册数据库的观察者 + // 当分布式数据库中的数据发生更改时,将调用回调 + store.on('dataChange', relationalStore.SubscribeType.SUBSCRIBE_TYPE_REMOTE, observer); + } catch (err) { + console.error('Failed to register observer. Code:${err.code},message:${err.message}'); + } + + // 当前不需要订阅数据变化时,可以将其取消。 + try { + store.off('dataChange', relationalStore.SubscribeType.SUBSCRIBE_TYPE_REMOTE, observer); + } catch (err) { + console.error('Failed to register observer. Code:${err.code},message:${err.message}'); + } + ``` + +6. 跨设备查询。如果数据未完成同步,或未触发数据同步,应用可以使用此接口从指定的设备上查询数据。 + + > **说明:** + > + > deviceIds通过调用[devManager.getTrustedDeviceListSync](../reference/apis/js-apis-device-manager.md#gettrusteddevicelistsync)方法得到,deviceManager模块的接口均为系统接口,仅系统应用可用。 + + + ```js + // 获取deviceIds + import deviceManager from '@ohos.distributedHardware.deviceManager'; + + deviceManager.createDeviceManager("com.example.appdatamgrverify", (err, manager) => { + if (err) { + console.info(`Failed to create device manager. Code:${err.code},message:${err.message}`); + return; + } + let devices = manager.getTrustedDeviceListSync(); + let deviceId = devices[0].deviceId; + + // 构造用于查询分布式表的谓词对象 + let predicates = new relationalStore.RdbPredicates('EMPLOYEE'); + // 调用跨设备查询接口,并返回查询结果 + store.remoteQuery(deviceId, 'EMPLOYEE', predicates, ['ID', 'NAME', 'AGE', 'SALARY', 'CODES'], + function (err, resultSet) { + if (err) { + console.error(`Failed to remoteQuery data. Code:${err.code},message:${err.message}`); + return; + } + console.info(`ResultSet column names: ${resultSet.columnNames}, column count: ${resultSet.columnCount}`); + } + ) + }) + ``` diff --git a/zh-cn/application-dev/database/database-datashare-guidelines.md b/zh-cn/application-dev/database/database-datashare-guidelines.md deleted file mode 100644 index 3ed0ccedd53ccc1a959110440edb42232534266b..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/database/database-datashare-guidelines.md +++ /dev/null @@ -1,304 +0,0 @@ -# 数据共享开发指导 -DataShare即数据共享模块,提供了向其他应用共享以及管理其数据的方法。目前仅支持同个设备上应用之间的数据共享。 - -## 接口说明 - -**表1** 数据提供方API说明 - -|接口名|描述| -|:------|:------| -|onCreate?(want: Want, callback: AsyncCallback<void>): void|DataShareExtensionAbility生命周期回调,在数据提供方应用创建时回调,执行初始化业务逻辑操作,如创建数据库。| -|insert?(uri: string, valueBucket: ValuesBucket, callback: AsyncCallback<number>): void|业务函数,在访问方向数据库中插入数据时回调。| -|update?(uri: string, predicates: DataSharePredicates, valueBucket: ValuesBucket, callback: AsyncCallback<number>): void|业务函数,在访问方更新数据时回调。| -|query?(uri: string, predicates: DataSharePredicates, columns: Array<string>, callback: AsyncCallback<Object>): void|业务函数,在访问方查询数据时回调。| -|delete?(uri: string, predicates: DataSharePredicates, callback: AsyncCallback<number>): void|业务函数,在访问方删除数据时回调。| - -完整的数据提供方接口请见[DataShareExtensionAbility](../reference/apis/js-apis-application-dataShareExtensionAbility.md)。 - -**表2** 数据访问方API说明 - -| 接口名 | 描述 | -| :----------------------------------------------------------- | :--------------------------------- | -| createDataShareHelper(context: Context, uri: string, callback: AsyncCallback<DataShareHelper>): void | 创建DataShare工具类。 | -| insert(uri: string, value: ValuesBucket, callback: AsyncCallback<number>): void | 将单条数据记录插入数据库。 | -| update(uri: string, predicates: DataSharePredicates, value: ValuesBucket, callback: AsyncCallback<number>): void | 更新数据库中的数据记录。 | -| query(uri: string, predicates: DataSharePredicates, columns: Array<string>, callback: AsyncCallback<DataShareResultSet>): void | 查询数据库中的数据。 | -| delete(uri: string, predicates: DataSharePredicates, callback: AsyncCallback<number>): void | 从数据库中删除一条或多条数据记录。 | - -完整的数据访问方接口请见[DataShareHelper](../reference/apis/js-apis-data-dataShare.md)。 - -## 开发场景 - -数据共享可分为数据的提供方和访问方两部分。 - -- 提供方可以选择性实现数据的增、删、改、查,以及文件打开等功能,并对外共享这些数据。 -- 访问方利用工具类,便可以访问提供方提供的这些数据。 - -以下是数据提供方和数据访问方应用的各自开发示例。 - -### 数据提供方应用的开发(仅限系统应用) - -[DataShareExtensionAbility](../reference/apis/js-apis-application-dataShareExtensionAbility.md)提供以下API,根据需要重写对应回调方法。 - -- **onCreate** - - DataShare客户端连接DataShareExtensionAbility服务端时,服务端回调此接口,执行初始化业务逻辑操作。该方法可以选择性重写。 - -- **insert** - - 业务函数,客户端请求插入数据时回调此接口,服务端需要在此回调中实现插入数据功能,该方法可以选择性重写。 - -- **update** - - 业务函数,客户端请求更新数据时回调此接口,服务端需要在此回调中实现更新数据功能,该方法可以选择性重写。 - -- **delete** - - 业务函数,客户端请求删除数据时回调此接口,服务端需要在此回调中实现删除数据功能,该方法可以选择性重写。 - -- **query** - - 业务函数,客户端请求查询数据时回调此接口,服务端需要在此回调中实现查询数据功能,该方法可以选择性重写。 - -- **batchInsert** - - 业务函数,客户端请求批量插入数据时回调此接口,服务端需要在此回调中实现批量插入数据数据功能,该方法可以选择性重写。 - -- **normalizeUri** - - 业务函数,客户端给定的URI转换为服务端使用的URI时回调此接口,该方法可以选择性重写。 - -- **denormalizeUri** - - 业务函数,服务端使用的URI转换为客户端传入的初始URI时服务端回调此接口,该方法可以选择性重写。 - -开发者在实现一个数据共享服务时,需要在DevEco Studio工程中手动新建一个DataShareExtensionAbility,具体步骤如下。 - -1. 在工程Module对应的ets目录下,右键选择“New > Directory”,新建一个目录并命名为DataShareAbility。 - -2. 在DataShareAbility目录,右键选择“New > TypeScript File”,新建一个TypeScript文件并命名为DataShareAbility.ts。 - -3. 在DataShareAbility.ts文件中,增加导入DataShareExtensionAbility的依赖包,开发者可根据应用需求选择性重写其业务实现。例如数据提供方只提供插入、删除和查询服务,则可只重写这些接口。 - - -4. 导入基础依赖包。 - - ```ts - import Extension from '@ohos.application.DataShareExtensionAbility'; - import rdb from '@ohos.data.relationalStore'; - import fileIo from '@ohos.fileio'; - import dataSharePredicates from '@ohos.data.dataSharePredicates'; - ``` - -5. 数据提供方(也称服务端)继承于DataShareExtensionAbility,开发者可根据应用需求选择性重写其业务实现。例如数据提供方只提供查询服务,则可只重写查询接口。 - -6. 数据提供方的业务实现由开发者自定义。例如可以通过数据库、读写文件或访问网络等各方式实现数据提供方的数据存储。 - - ```ts - const DB_NAME = "DB00.db"; - const TBL_NAME = "TBL00"; - const DDL_TBL_CREATE = "CREATE TABLE IF NOT EXISTS " - + TBL_NAME - + " (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, isStudent BOOLEAN, Binary BINARY)"; - - let rdbStore; - let result; - - export default class DataShareExtAbility extends Extension { - private rdbStore_; - - // 重写onCreate接口 - onCreate(want, callback) { - result = this.context.cacheDir + '/datashare.txt'; - // 业务实现使用RDB - rdb.getRdbStore(this.context, { - name: DB_NAME, - securityLevel: rdb.SecurityLevel.S1 - }, function (err, data) { - rdbStore = data; - rdbStore.executeSql(DDL_TBL_CREATE, [], function (err) { - console.log('DataShareExtAbility onCreate, executeSql done err:' + JSON.stringify(err)); - }); - if (callback) { - callback(); - } - }); - } - - // 重写query接口 - query(uri, predicates, columns, callback) { - if (predicates == null || predicates == undefined) { - console.info('invalid predicates'); - } - try { - rdbStore.query(TBL_NAME, predicates, columns, function (err, resultSet) { - if (resultSet != undefined) { - console.info('resultSet.rowCount: ' + resultSet.rowCount); - } - if (callback != undefined) { - callback(err, resultSet); - } - }); - } catch (err) { - console.error('error' + err); - } - } - // 可根据应用需求,选择性重写各个接口 - // ... - }; - ``` - -7. 在module.json5中定义DataShareExtensionAbility。 - - | Json重要字段 | 备注说明 | 必填 | - | ------------ | ------------------------------------------------------------ | --- | - | "name" | Ability名称,对应Ability派生的ExtensionAbility类名。 | 是 | - | "type" | Ability类型,DataShare对应的Ability类型为”dataShare“,表示基于datashare模板开发的。 | 是 | - | "uri" | 通信使用的URI,是客户端链接服务端的唯一标识。 | 是 | - | "visible" | 对其他应用是否可见,设置为true时,才能与其他应用进行通信传输数据。 | 是 | - | "metadata" | 增加静默访问所需的额外配置项,包含name和resource字段。
name类型固定为"ohos.extension.dataShare",是配置的唯一标识。
resource类型固定为"$profile:data_share_config",表示配置文件的名称为data_share_config.json. | 若Ability启动模式为"singleton",则metadata必填,Ability启动模式可见[abilities对象的内部结构-launchType](../quick-start/module-structure.md#abilities对象的内部结构);其他情况下选填。 | - - **module.json5配置样例** - - ```json - "extensionAbilities": [ - { - "srcEntrance": "./ets/DataShareExtAbility/DataShareExtAbility.ts", - "name": "DataShareExtAbility", - "icon": "$media:icon", - "description": "$string:description_datashareextability", - "type": "dataShare", - "uri": "datashare://com.samples.datasharetest.DataShare", - "visible": true, - "metadata": [{"name": "ohos.extension.dataShare", "resource": "$profile:data_share_config"}] - } - ] - ``` - - **data_share_config.json说明** - - | 字段 | 备注说明 | 必填 | - | ------------ | ------------------------------------------------------------ | --- | - | "tableConfig" | 配置标签。 | 是 | - | "uri" | 指定配置生效的范围,uri支持以下三种格式,优先级为**表配置>库配置>\***,如果同时配置,高优先级会覆盖低优先级 。
1. "*" : 所有的数据库和表。
2. "datashare:///{bundleName}/{moduleName}/{storeName}" : 指定数据库。
3. "datashare:///{bundleName}/{moduleName}/{storeName}/{tableName}" : 指定表。 | 是 | - | "crossUserMode" | 标识数据是否为多用户共享,配置为1则多用户数据共享,配置为2则多用户数据隔离。 | 若Ability启动模式为"singleton",则metadata必填,Ability启动模式可见[abilities对象的内部结构-launchType](../quick-start/module-structure.md#abilities对象的内部结构);其他情况下不填。 | - | "writePermission" | 静默访问需要的写权限。 | 否 | - | "readPermission" | 静默访问需要的读权限。 | 否 | - - **data_share_config.json配置样例** - - ```json - "tableConfig": [ - { - "uri": "*", - "writePermission": "ohos.permission.xxx" - }, - { - "uri": "datashare:///com.acts.datasharetest/entry/DB00", - "crossUserMode": 1, - "writePermission": "ohos.permission.xxx", - "readPermission": "ohos.permission.xxx" - }, - { - "uri": "datashare:///com.acts.datasharetest/entry/DB00/TBL00", - "crossUserMode": 2 - } - ] - ``` - -### 数据访问方应用的开发 - -1. 导入基础依赖包。 - - ```ts - import UIAbility from '@ohos.app.ability.UIAbility'; - import dataShare from '@ohos.data.dataShare'; - import dataSharePredicates from '@ohos.data.dataSharePredicates'; - ``` - -2. 定义与数据提供方通信的URI字符串。 - - ```ts - // 作为参数传递的URI,与module.json5中定义的URI的区别是多了一个"/",是因为作为参数传递的URI中,在第二个与第三个"/"中间,存在一个DeviceID的参数 - let dseUri = ('datashare:///com.samples.datasharetest.DataShare'); - ``` - -3. 创建工具接口类对象。 - - ```ts - let dsHelper; - let abilityContext; - - export default class EntryAbility extends UIAbility { - onWindowStageCreate(windowStage) { - abilityContext = this.context; - dataShare.createDataShareHelper(abilityContext, dseUri, (err, data)=>{ - dsHelper = data; - }); - } - } - ``` - -4. 获取到接口类对象后,便可利用其提供的接口访问提供方提供的服务,如进行数据的增删改查等。 - - ```ts - // 构建一条数据 - let valuesBucket = { "name": "ZhangSan", "age": 21, "isStudent": false, "Binary": new Uint8Array([1, 2, 3]) }; - let updateBucket = { "name": "LiSi", "age": 18, "isStudent": true, "Binary": new Uint8Array([1, 2, 3]) }; - let predicates = new dataSharePredicates.DataSharePredicates(); - let valArray = ['*']; - // 插入一条数据 - dsHelper.insert(dseUri, valuesBucket, (err, data) => { - console.log('dsHelper insert result: ' + data); - }); - // 更新数据 - dsHelper.update(dseUri, predicates, updateBucket, (err, data) => { - console.log('dsHelper update result: ' + data); - }); - // 查询数据 - dsHelper.query(dseUri, predicates, valArray, (err, data) => { - console.log('dsHelper query result: ' + data); - }); - // 删除指定的数据 - dsHelper.delete(dseUri, predicates, (err, data) => { - console.log('dsHelper delete result: ' + data); - }); - ``` -## 限制 - -为了降低DataShareExtensionAbility能力被三方应用滥用的风险,在DataShareExtensionAbility中限制以下接口的调用 -- ./application/UIAbilityContext -- @ohos.ability.featureAbility.d.ts -- @ohos.ability.particleAbility.d.ts -- @ohos.account.osAccount.d.ts -- @ohos.backgroundTaskManager.d.ts -- @ohos.bluetooth.d.ts -- @ohos.bluetoothManager.d.ts -- @ohos.connectedTag.d.ts -- @ohos.continuation.continuationManage.d.ts -- @ohos.mutilmedia.audio.d.ts -- @ohos.multimedia.carema.d.ts -- @ohos.nfc.cardEmulation.d.ts -- @ohos.nfc.controller.d.ts -- @ohos.nfc.tag.d.ts -- @ohos.request.d.ts -- @ohos.resourceschedule.backgroundTaskManager.d.ts -- @ohos.telephony.call.d.ts -- @ohos.telephony.data.d.ts -- @ohos.telephony.observer.d.ts -- @ohos.telephony.radio.d.ts -- @ohos.telephony.sim.d.ts -- @ohos.telephony.sms.d.ts -- @ohos.vibrator.d.ts -- @ohos.wallpaper.d.ts -- @ohos.wifi.d.ts -- @ohos.wifiext.d.ts -- @ohos.wifiManager.d.ts -- @ohos.wifiManagerExt.d.ts -- @ohos.window.d.ts - -## 相关示例 - -针对DataShareExtensionAbility开发,有以下相关示例可供参考: - -[DataShareExtensionAbility:跨应用数据共享(ArkTS)(API9)(Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/master/data/CrossAppDataShare) diff --git a/zh-cn/application-dev/database/database-datashare-overview.md b/zh-cn/application-dev/database/database-datashare-overview.md deleted file mode 100644 index 179f92808ed31c5a93419a8aeb91f26067317111..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/database/database-datashare-overview.md +++ /dev/null @@ -1,56 +0,0 @@ -# 数据共享概述 - -## 数据共享简介 - -DataShare即数据共享模块,用于应用管理其自身数据,也提供了向其他应用共享以及管理其数据的方法。目前仅支持同个设备上应用之间的数据共享。 - -DataShare需要与[DataShareExtensionAbility](../reference/apis/js-apis-application-dataShareExtensionAbility.md)配合使用。 - -在许多应用场景中都需要用到数据共享,比如将电话簿、短信、媒体库中的数据共享给其他应用等。当然,不是所有的数据都允许其他应用访问,比如帐号、密码等;有些数据也只允许其他应用查询而不允许其删改,比如短信等。所以对于各种数据共享场景,DataShare这样一个安全、便捷的可以跨应用的数据共享机制是十分必需的。 - -对于数据提供者来说,无需进行繁琐的封装,可直接使用DataShare框架实现向其他应用共享数据;对于数据访问方来说,因DataShare的访问方式不会因数据提供的方式而不同,所以只需要学习和使用一套接口即可,大大减少了学习时间和开发难度。 - -## 基本概念 - - -在进行应用的开发前,开发者应了解以下基本概念: - - -- **数据提供方** - - DataShareExtensionAbility,基于Stage模型,选择性实现对数据的增、删、改、查以及文件打开等功能,并对外共享这些数据。实现跨应用数据共享的相关业务。 - -- **数据访问方** - - DataShareHelper,由[createDataShareHelper()](../reference/apis/js-apis-data-dataShare.md#datasharecreatedatasharehelper)方法所创建的工具类,数据访问方利用工具类,便可访问数据提供方提供的数据。 - -- **数据集** - - 用户要插入的数据集合,可以是一条或多条数据。数据集以键值对的形式存在,键为字符串类型,值支持数字、字符串、布尔值、无符号整型数组等多种数据类型。 - -- **结果集** - - 用户查询之后的结果集合,其提供了灵活的数据访问方式,以便用户获取各项数据。 - -- **谓词** - - 用户访问数据库中的数据所使用的筛选条件,经常被应用在更新数据、删除数据和查询数据等场景。 - -## 运作机制 - -**图 1** DataShare运作机制 - - -![](figures/zh-cn_DataShare.png) - -- DataShareExtensionAbility模块为数据提供方,实现跨应用数据共享的相关业务。 -- DataShareHelper模块为数据访问方,提供各种访问数据的接口,包括增删改查等。 -- 数据访问方与提供方通过IPC进行通信,数据提供方可以通过数据库实现,也可以通过其他数据存储方式实现。 - -- ResultSet模块通过共享内存实现,用于存储查询数据得到的结果集,并提供了遍历结果集的方法。 - -## 约束与限制 - -- DataShare受到数据提供方所使用数据库的一些限制。例如支持的数据模型、Key的长度、Value的长度、每个应用程序支持同时打开数据库的最大数量等,都会受到使用的数据库的限制。 - -- 因DataShare内部实现依赖于IPC通信,所以数据集、谓词、结果集等的载荷受到IPC通信的约束与限制。 diff --git a/zh-cn/application-dev/database/database-distributedobject-guidelines.md b/zh-cn/application-dev/database/database-distributedobject-guidelines.md deleted file mode 100644 index 78a92e0c2d76ff269ecff80337fdaf72c0cdadfe..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/database/database-distributedobject-guidelines.md +++ /dev/null @@ -1,282 +0,0 @@ -# 分布式数据对象开发指导 - -## 场景介绍 - -分布式数据对象为开发者在分布式应用场景下提供简单易用的功能接口,可实现多设备间同应用的数据协同,同时设备间还可以监听对象的状态和数据变更。 - -比如,当设备1上应用A的分布式数据对象增、删、改数据后,设备2上应用A也可以获取到对应的数据变化,同时还能监听数据变更以及对端数据对象的上下线。 - -## 接口说明 - -分布式数据对象相关功能接口请见[分布式数据对象](../reference/apis/js-apis-data-distributedobject.md)。 - -### 创建数据对象实例 - -创建一个分布式数据对象实例,开发者可以通过source指定分布式数据对象中的属性。 - - -**表1** 分布式数据对象实例创建接口 - -| Bundle名称 | 接口名 | 描述 | -| -------- | -------- | -------- | -| ohos.data.distributedDataObject| createDistributedObject(source: object): DistributedObject | 创建一个分布式数据对象实例,用于数据操作。
- source:设置分布式数据对象的属性。
- DistributedObject:返回值是创建好的分布式数据对象。 | - -### 创建分布式数据对象sessionId - -创建一个随机的sessionId,可将其设置为一个分布式数据对象的sessionId。 - -**表2** 分布式数据对象sessionId创建接口 - -| Bundle名称 | 接口名 | 描述 | -| -------- | -------- | -------- | -| ohos.data.distributedDataObject| genSessionId(): string | 创建一个sessionId,可作为分布式数据对象的sessionId。 | - -### 设置分布式数据对象sessionId - -设置分布式数据对象的sessionId,sessionId是一次(多设备)协同的唯一标识,同步的多个数据对象需要关联同一个sessionId。 - -**表3** 分布式数据对象sessionId设置接口 - -| 类名 | 接口名 | 描述 | -| -------- | -------- | -------- | -| DistributedDataObject | setSessionId(sessionId?: string): boolean | 为分布式数据对象设置sessionId。
 sessionId:分布式数据对象在可信组网中的标识ID。如果要退出分布式组网,设置为""或不设置均可。 | - -### 订阅数据变更 - -订阅数据变更需要指定Callback作为回调方法,订阅的数据对象发生数据变更后,Callback被回调。 - -**表4** 分布式数据对象数据变更订阅接口 - -| 类名 | 接口名 | 描述 | -| -------- | -------- | -------- | -| DistributedDataObject| on(type: 'change', callback: Callback<{ sessionId: string, fields: Array<string> }>): void | 订阅数据变更。 | -| DistributedDataObject| off(type: 'change', callback?: Callback<{ sessionId: string, fields: Array<string> }>): void | 注销订阅。需要删除的变更回调,若不设置则删除该对象所有的变更回调。 | - -### 订阅数据对象上下线 - -订阅数据对象上下线需要指定Callback作为回调方法,订阅的数据对象上线/下线后,对端的数据对象会收到Callback回调。 - -**表5** 分布式数据对象数据上下线订阅接口 - -| 类名 | 接口名 | 描述 | -| -------- | -------- | -------- | -| DistributedDataObject| on(type: 'status', callback: Callback<{ sessionId: string, networkId: string, status: 'online' \| 'offline' }>): void | 订阅数据对象上下线。 | -| DistributedDataObject| off(type: 'status', callback?: Callback<{ sessionId: string, deviceId: string, status: 'online' \| 'offline' }>): void | 注销订阅。 | - -### 保存和撤回已保存的数据对象 - -保存数据对象:数据对象保存成功后,当应用存在时不会释放对象数据;当应用退出后,重新进入应用时,恢复保存在设备上的数据。 - -撤回保存的数据对象:如果该对象保存在本地设备,那么将删除所有受信任设备上所保存的数据;如果对象保存在其他设备,那么将删除本地设备上的数据。 - -有以下几种情况时,保存的数据将会被释放: - -- 存储时间超过24小时。 -- 应用卸载。 -- 成功恢复数据之后。 - -**表6** 分布式数据对象保存和撤回保存接口 - -| 类名 | 接口名 | 描述 | -| -------- | -------- | -------- | -| DistributedDataObject | save(deviceId: string): Promise<SaveSuccessResponse> | 保存数据对象。 | -| DistributedDataObject| revokeSave(): Promise<RevokeSaveSuccessResponse> | 撤回已保存的数据对象。 | - -## 开发步骤 - -以一次分布式数据对象同步为例,说明开发步骤。 - -1. 准备工作,导入@ohos.data.distributedDataObject模块到开发环境。 - - ```js - import distributedObject from '@ohos.data.distributedDataObject'; - ``` -2. 请求权限。 - - 需要在`config.json`文件里进行配置请求权限(FA模型)。 - - ```json - { - "module": { - "reqPermissions": [ - { - "name": "ohos.permission.DISTRIBUTED_DATASYNC" - } - ] - } - } - ``` - Stage模型下的权限请求请参见[权限声明-Stage模型](../security/accesstoken-guidelines.md#stage模型)。 - - 这个权限还需要在应用首次启动的时候弹窗获取用户授权。 - - ```js - // FA模型 - import featureAbility from '@ohos.ability.featureAbility'; - - function grantPermission() { - console.info('grantPermission'); - let context = featureAbility.getContext(); - context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) { - console.info(`requestPermissionsFromUser CallBack`); - - }) - console.info('end grantPermission'); - } - - grantPermission(); - ``` - - ```ts - // Stage模型 - import UIAbility from '@ohos.app.ability.UIAbility'; - - let context = null; - - class EntryAbility extends UIAbility { - onWindowStageCreate(windowStage) { - context = this.context; - } - } - - function grantPermission() { - let permissions = ['ohos.permission.DISTRIBUTED_DATASYNC']; - context.requestPermissionsFromUser(permissions).then((data) => { - console.info('success: ${data}'); - }).catch((error) => { - console.error('failed: ${error}'); - }); - } - - grantPermission(); - ``` - -3. 获取分布式数据对象实例。 - - ```js - let localObject = distributedObject.createDistributedObject({ - name: undefined, - age: undefined, - isVis: true, - parent: undefined, - list: undefined - }); - let sessionId = distributedObject.genSessionId(); - ``` - -4. 加入同步组网。同步组网中的数据对象分为发起方和被拉起方。 - - ```js - // 发起方 - let localObject = distributedObject.createDistributedObject({ - name: "jack", - age: 18, - isVis: true, - parent: { mother: "jack mom", father: "jack Dad" }, - list: [{ mother: "jack mom" }, { father: "jack Dad" }] - }); - localObject.setSessionId(sessionId); - - // 被拉起方 - let remoteObject = distributedObject.createDistributedObject({ - name: undefined, - age: undefined, - isVis: true, - parent: undefined, - list: undefined - }); - // 收到status上线后remoteObject同步数据,即name变成jack,age是18 - remoteObject.setSessionId(sessionId); - ``` - -5. 监听对象数据变更。可监听对端数据的变更,以Callback作为变更回调实例。 - - ```js - function changeCallback(sessionId, changeData) { - console.info("change" + sessionId); - - if (changeData != null && changeData != undefined) { - changeData.forEach(element => { - console.info("changed !" + element + " " + localObject[element]); - }); - } - } - - // 发起方要在changeCallback里刷新界面,则需要将正确的this绑定给changeCallback - localObject.on("change", this.changeCallback.bind(this)); - ``` - -6. 修改对象属性,对象属性支持基本类型(数字类型、布尔类型、字符串类型)以及复杂类型(数组、基本类型嵌套等)。 - - ```js - localObject.name = "jack"; - localObject.age = 19; - localObject.isVis = false; - localObject.parent = { mother: "jack mom", father: "jack Dad" }; - localObject.list = [{ mother: "jack mom" }, { father: "jack Dad" }]; - ``` - - > **说明:** - > 针对复杂类型的数据修改,目前支持对根属性的修改,暂不支持对下级属性的修改。 - - ```js - // 支持的修改方式 - localObject.parent = { mother: "mom", father: "dad" }; - // 不支持的修改方式 - localObject.parent.mother = "mom"; - ``` - -7. 访问对象。可以通过直接获取的方式访问到分布式数据对象的属性,且该数据为组网内的最新数据。 - - ```js - console.info("name " + localObject["name"]); - ``` -8. 删除监听数据变更。可以指定删除监听的数据变更回调;也可以不指定,这将会删除该分布式数据对象的所有数据变更回调。 - - ```js - // 删除变更回调changeCallback - localObject.off("change", changeCallback); - // 删除所有的变更回调 - localObject.off("change"); - ``` -9. 监听分布式数据对象的上下线。可以监听对端分布式数据对象的上下线。 - - ```js - function statusCallback(sessionId, networkId, status) { - this.response += "status changed " + sessionId + " " + status + " " + networkId; - } - - localObject.on("status", this.statusCallback); - ``` - -10. 保存和撤回已保存的数据对象。 - - ```js - // 保存数据对象 - localObject.save("local").then((result) => { - console.info("save sessionId " + result.sessionId); - console.info("save version " + result.version); - console.info("save deviceId " + result.deviceId); - }, (result) => { - console.info("save local failed."); - }); - // 撤回保存的数据对象 - localObject.revokeSave().then((result) => { - console.info("revokeSave success."); - }, (result) => { - console.info("revokeSave failed."); - }); - ``` -11. 删除监听分布式数据对象的上下线。可以指定删除监听的上下线回调;也可以不指定,这将会删除该分布式数据对象的所有上下线回调。 - - ```js - // 删除上下线回调statusCallback - localObject.off("status", this.statusCallback); - // 删除所有的上下线回调 - localObject.off("status"); - ``` -12. 退出同步组网。分布式数据对象退出组网后,本地的数据变更对端不会同步。 - - ```js - localObject.setSessionId(""); - ``` diff --git a/zh-cn/application-dev/database/database-distributedobject-overview.md b/zh-cn/application-dev/database/database-distributedobject-overview.md deleted file mode 100644 index 457cf83db217e6b8f183bd768108966880f6ce67..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/database/database-distributedobject-overview.md +++ /dev/null @@ -1,46 +0,0 @@ -# 分布式数据对象概述 - -分布式数据对象管理框架是一款面向对象的内存数据管理框架。向应用开发者提供内存对象的创建、查询、删除、修改、订阅等基本数据对象的管理能力;同时具备分布式能力,满足超级终端场景下,相同应用多设备间的数据对象协同需求。 - - -## 基本概念 - -- **分布式内存数据库** - - 分布式内存数据库将数据缓存在内存中,以便应用获得更快的数据存取速度,不会将数据进行持久化。若数据库关闭,则数据不会保留。 - - -- **分布式数据对象** - - 分布式数据对象是一个JS对象型的封装。每一个分布式数据对象实例会创建一个内存数据库中的数据表,每个应用程序创建的内存数据库相互隔离,对分布式数据对象的“读取”或“赋值”会自动映射到对应数据库的get/put操作。 - - 分布式数据对象的生命周期包括以下状态: - - - **未初始化**:未实例化,或已被销毁。 - - **本地数据对象**:已创建对应的数据表,但是还无法进行数据同步。 - - **分布式数据对象**:已创建对应的数据表,设备在线且组网内设置同样sessionId的对象数>=2,可以跨设备同步数据。若设备掉线或将sessionId置为空,分布式数据对象退化为本地数据对象。 - - -## 运作机制 - -分布式数据对象生长在分布式内存数据库之上,在分布式内存数据库上进行了JS对象型的封装,能像操作本地变量一样操作分布式数据对象,数据的跨设备同步由系统自动完成。 - -**图1** 分布式数据对象运行机制 - -![how-distributedobject-works](figures/how-distributedobject-works.png) - - - - -## 约束与限制 - -- 不同设备间只有相同bundleName的应用才能直接同步。 - -- 不建议创建过多的分布式数据对象,每个分布式数据对象将占用100-150KB内存。 - -- 每个分布式数据对象大小不超过500KB。 - -- 如对复杂类型的数据进行修改,仅支持修改根属性,暂不支持下级属性修改。 - -- 支持JS接口间的互通,与其他语言不互通。 - diff --git a/zh-cn/application-dev/database/database-mdds-guidelines.md b/zh-cn/application-dev/database/database-mdds-guidelines.md deleted file mode 100644 index cd07fe5706b1f3ec0e83da3338bba53df47054c5..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/database/database-mdds-guidelines.md +++ /dev/null @@ -1,272 +0,0 @@ -# 分布式数据服务开发指导 - -## 场景介绍 - -分布式数据服务主要实现用户设备中应用程序数据内容的分布式同步。当设备1上的应用A在分布式数据库中增、删、改数据后,设备2上的应用A也可以获取到该数据库变化。可在分布式图库、信息、通讯录、文件管理器等场景中使用。 - - -## 接口说明 - -分布式数据相关功能接口请见[分布式键值数据库](../reference/apis/js-apis-distributedKVStore.md)。 - -**表1** 分布式数据服务关键API功能介绍 - -| 接口名称 | 描述 | -| ------------------------------------------------------------ | ------------------------------------------------------------ | -| createKVManager(config: KVManagerConfig): KVManager | 创建一个`KVManager`对象实例,用于管理数据库对象。 | -| getKVStore<T extends KVStore>(storeId: string, options: Options, callback: AsyncCallback<T>): void
getKVStore<T extends KVStore>(storeId: string, options: Options): Promise<T> | 指定`Options`和`storeId`,创建并获取指定类型`KVStore`数据库。 | -| put(key: string, value: Uint8Array\|string\|number\|boolean, callback: AsyncCallback<void>): void
put(key: string, value: Uint8Array\|string\|number\|boolean): Promise<void> | 插入和更新数据。 | -| delete(key: string, callback: AsyncCallback<void>): void
delete(key: string): Promise<void> | 删除数据。 | -| get(key: string, callback: AsyncCallback<Uint8Array\|string\|boolean\|number>): void
get(key: string): Promise<Uint8Array\|string\|boolean\|number> | 获取数据。 | -| on(event: 'dataChange', type: SubscribeType, observer: Callback<ChangeNotification>): void
on(event: 'syncComplete', syncCallback: Callback<Array<[string,number]>>): void | 订阅数据库中数据的变化。 | -| sync(deviceIdList: string[], mode: SyncMode, delayMs?: number): void | 在手动模式下,触发数据库同步。 | - -## 开发步骤 - -以单版本分布式数据库为例,说明开发步骤。 - -1. 导入模块。 - - ```js - import distributedKVStore from '@ohos.data.distributedKVStore'; - ``` - -2. 请求权限(同步操作时进行该步骤)。 - - 需要在`config.json`文件里进行配置请求权限(FA模型),示例代码如下: - - ```json - { - "module": { - "reqPermissions": [ - { - "name": "ohos.permission.DISTRIBUTED_DATASYNC" - } - ] - } - } - ``` - - Stage模型下的权限请求请参见[权限声明-Stage模型](../security/accesstoken-guidelines.md#stage模型)。 - - 这个权限还需要在应用首次启动的时候弹窗获取用户授权,可以通过如下代码实现: - - ```js - // FA模型 - import featureAbility from '@ohos.ability.featureAbility'; - - function grantPermission() { - console.info('grantPermission'); - let context = featureAbility.getContext(); - context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666).then((data) => { - console.info('success: ${data}'); - }).catch((error) => { - console.error('failed: ${error}'); - }) - } - - grantPermission(); - - // Stage模型 - import UIAbility from '@ohos.app.ability.UIAbility'; - - let context = null; - - class EntryAbility extends UIAbility { - onWindowStageCreate(windowStage) { - let context = this.context; - } - } - - function grantPermission() { - let permissions = ['ohos.permission.DISTRIBUTED_DATASYNC']; - context.requestPermissionsFromUser(permissions).then((data) => { - console.log('success: ${data}'); - }).catch((error) => { - console.error('failed: ${error}'); - }); - } - - grantPermission(); - ``` - -3. 根据配置构造分布式数据库管理类实例。 - - 1. 根据应用上下文创建`kvManagerConfig`对象。 - 2. 创建分布式数据库管理器实例。 - - 以下为创建分布式数据库管理器的代码示例: - - ```js - // FA模型获取context - import featureAbility from '@ohos.ability.featureAbility'; - let context = featureAbility.getContext(); - - // Stage模型获取context - import UIAbility from '@ohos.app.ability.UIAbility'; - let context = null; - class EntryAbility extends UIAbility { - onWindowStageCreate(windowStage){ - context = this.context; - } - } - - let kvManager; - try { - const kvManagerConfig = { - bundleName: 'com.example.datamanagertest', - context:context, - } - kvManager = distributedKVStore.createKVManager(kvManagerConfig); - console.log("Succeeded in creating KVManager"); - } catch (e) { - console.error(`Failed to create KVManager.code is ${e.code},message is ${e.message}`); - } - ``` - -4. 获取/创建分布式数据库。 - - 1. 声明需要创建的分布式数据库ID描述。 - 2. 创建分布式数据库,建议关闭自动同步功能(`autoSync:false`),需要同步时主动调用`sync`接口。 - - 以下为创建分布式数据库的代码示例: - - ```js - let kvStore; - try { - const options = { - createIfMissing: true, - encrypt: false, - backup: false, - autoSync: false, - kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, - securityLevel: distributedKVStore.SecurityLevel.S1 - }; - kvManager.getKVStore('storeId', options, function (err, store) { - if (err) { - console.error(`Failed to get KVStore: code is ${err.code},message is ${err.message}`); - return; - } - console.log('Succeeded in getting KVStore'); - kvStore = store; - }); - } catch (e) { - console.error(`An unexpected error occurred.code is ${e.code},message is ${e.message}`); - } - ``` - - > **说明:** - > - > 组网设备间同步数据的场景,建议在应用启动时打开分布式数据库,获取数据库的句柄。在该句柄(如示例中的`kvStore`)的生命周期内无需重复创建数据库,可直接使用句柄对数据库进行数据的插入等操作。 - -5. 订阅分布式数据变化。 - - 以下为订阅单版本分布式数据库数据变化通知的代码示例: - - ```js - try{ - kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, function (data) { - console.log(`dataChange callback call data: ${data}`); - }); - }catch(e){ - console.error(`An unexpected error occured.code is ${e.code},message is ${e.message}`); - } - ``` - -6. 将数据写入分布式数据库。 - - 1. 构造需要写入分布式数据库的`Key`(键)和`Value`(值)。 - 2. 将键值数据写入分布式数据库。 - - 以下为将字符串类型键值数据写入分布式数据库的代码示例: - - ```js - const KEY_TEST_STRING_ELEMENT = 'key_test_string'; - const VALUE_TEST_STRING_ELEMENT = 'value-test-string'; - try { - kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, function (err,data) { - if (err != undefined) { - console.error(`Failed to put.code is ${err.code},message is ${err.message}`); - return; - } - console.log("Succeeded in putting"); - }); - }catch (e) { - console.error(`An unexpected error occurred.code is ${e.code},message is ${e.message}`); - } - ``` - -7. 查询分布式数据库数据。 - - 1. 构造需要从单版本分布式数据库中查询的`Key`(键)。 - 2. 从单版本分布式数据库中获取数据。 - - 以下为从分布式数据库中查询字符串类型数据的代码示例: - - ```js - const KEY_TEST_STRING_ELEMENT = 'key_test_string'; - const VALUE_TEST_STRING_ELEMENT = 'value-test-string'; - try { - kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, function (err,data) { - if (err != undefined) { - console.error(`Failed to put.code is ${err.code},message is ${err.message}`); - return; - } - console.log("Succeeded in putting"); - kvStore.get(KEY_TEST_STRING_ELEMENT, function (err,data) { - if (err != undefined) { - console.error(`Failed to get.code is ${err.code},message is ${err.message}`); - return; - } - console.log(`Succeeded in getting data:${data}`); - }); - }); - }catch (e) { - console.error(`Failed to get.code is ${e.code},message is ${e.message}`); - } - ``` - -8. 同步数据到其他设备。 - - 选择同一组网环境下的设备以及同步模式,进行数据同步。 - - > **说明**: - > - > 其中`deviceManager`模块的接口均为系统接口。 - - 以下为单版本分布式数据库进行数据同步的代码示例: - - ```js - import deviceManager from '@ohos.distributedHardware.deviceManager'; - - let devManager; - // create deviceManager - deviceManager.createDeviceManager('bundleName', (err, value) => { - if (!err) { - devManager = value; - // deviceIds由deviceManager调用getTrustedDeviceListSync方法得到 - let deviceIds = []; - if (devManager != null) { - var devices = devManager.getTrustedDeviceListSync(); - for (var i = 0; i < devices.length; i++) { - deviceIds[i] = devices[i].deviceId; - } - } - try{ - // 1000表示最大延迟时间为1000ms - kvStore.sync(deviceIds, distributedKVStore.SyncMode.PUSH_ONLY, 1000); - } catch (e) { - console.error(`An unexpected error occurred. code is ${e.code},message is ${e.message}`); - } - } - }); - ``` - -## 相关实例 - -针对分布式数据开发,有以下相关实例可供参考: - -- [`ArkTSDistributedCalc`:分布式计算器(ArkTS)(API9)(Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/master/code/SuperFeature/DistributedAppDev/ArkTSDistributedCalc) -- [`DistributedDataGobang`:分布式五子棋(ArkTS)(API9)(Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/master/code/Solutions/Game/DistributedDataGobang) -- [`KvStore`:分布式数据库(ArkTS)(API9)(Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/master/code/SuperFeature/DistributedAppDev/Kvstore) -- [分布式数据库(JS)(API8)](https://gitee.com/openharmony/codelabs/tree/master/Data/JsDistributedData) \ No newline at end of file diff --git a/zh-cn/application-dev/database/database-mdds-overview.md b/zh-cn/application-dev/database/database-mdds-overview.md deleted file mode 100644 index d2dccbe67c3af16f73c284930146c1c6277c309d..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/database/database-mdds-overview.md +++ /dev/null @@ -1,101 +0,0 @@ -# 分布式数据服务概述 - -分布式数据服务(Distributed Data Service,DDS)为应用程序提供不同设备间数据库的分布式协同能力。 - -通过调用分布式数据接口,应用程序将数据保存到分布式数据库中。通过结合帐号、应用和数据库三元组,分布式数据服务对属于不同应用的数据进行隔离,保证不同应用之间的数据不能通过分布式数据服务互相访问。在通过可信认证的设备间,分布式数据服务支持应用数据相互同步,为用户提供在多种终端设备上最终一致的数据访问体验。 - -关于数据库锁机制,开发者无需关注其具体实现。 - - -## 基本概念 - -### KV数据模型 - -“KV数据模型”是“Key-Value数据模型”的简称,“Key-Value”即“键-值”;其数据以键值对的形式进行组织、索引和存储。 - -KV数据模型适合不涉及过多数据关系和业务关系的业务数据存储,比SQL数据库存储拥有更好的读写性能,同时因其在分布式场景中降低了解决数据库版本兼容问题的复杂度,和数据同步过程中冲突解决的复杂度而被广泛使用。分布式数据库也是基于KV数据模型,对外提供KV类型的访问接口。 - -### 分布式数据库事务性 - -分布式数据库事务支持本地事务(和传统数据库的事务概念一致)和同步事务。同步事务是指在设备之间同步数据时,以本地事务为单位进行同步,一次本地事务的修改要么都同步成功,要么都同步失败。 - -### 分布式数据库一致性 - -在分布式场景中一般会涉及多个设备,组网内设备之间看到的数据是否一致称为分布式数据库的一致性。分布式数据库一致性可以分为**强一致性**、**弱一致性**和**最终一致性**。 - -- **强一致性**:是指某一设备成功增、删、改数据后,组网内设备对该数据的读取操作都将得到更新后的值。 -- **弱一致性**:是指某一设备成功增、删、改数据后,组网内设备可能读取到本次更新数据,也可能读取不到,不能保证在多长时间后每个设备的数据一定是一致的。 -- **最终一致性**:是指某一设备成功增、删、改数据后,组网内设备可能读取不到本次更新数据,但在某个时间窗口之后组网内设备的数据能够达到一致状态。 - -强一致性对分布式数据的管理要求非常高,在服务器的分布式场景可能会遇到。因为移动终端设备的不常在线、以及无中心的特性,分布式数据服务不支持强一致性,只支持最终一致性。 - -### 分布式数据库同步 - -底层通信组件完成设备发现和认证,会通知上层应用程序(包括分布式数据服务)设备上线。收到设备上线的消息后分布式数据服务可以在两个设备之间建立加密的数据传输通道,利用该通道在两个设备之间进行数据同步。 - -分布式数据服务提供了两种同步方式:**手动同步**和**自动同步**。 - -- **手动同步**:由应用程序调用sync接口来触发,需要指定同步的设备列表和同步模式。同步模式分为PULL_ONLY(将远端数据拉到本端)、PUSH_ONLY(将本端数据推送到远端)和PUSH_PULL(将本端数据推送到远端同时也将远端数据拉取到本端)。内部接口支持按条件过滤同步,将符合条件的数据同步到远端。 -- **自动同步**:包括全量同步和按条件订阅同步。全量同步由分布式数据库自动将本端数据推送到远端,同时也将远端数据拉取到本端来完成数据同步,同步时机包括设备上线、应用程序更新数据等,应用不需要主动调用sync接口;内部接口支持按条件订阅同步,将远端符合订阅条件的数据自动同步到本端。 - -### 单版本分布式数据库 - -单版本分布式数据库是指数据在本地保存是以单个KV条目为单位的方式保存,对每个Key最多只保存一个条目项,当数据在本地被用户修改时,不管它是否已经被同步出去,均直接在这个条目上进行修改。同步也以此为基础,按照它在本地被写入或更改的顺序将当前最新一次修改逐条同步至远端设备。 - -### 设备协同分布式数据库 - -设备协同分布式数据库建立在单版本分布式数据库之上,对应用程序存入的KV数据中的Key前面拼接了本设备的DeviceID标识符,这样能保证每个设备产生的数据严格隔离,底层按照设备的维度管理这些数据,设备协同分布式数据库支持以设备的维度查询分布式数据,但是不支持修改远端设备同步过来的数据。 - -### 分布式数据库冲突解决策略 - -分布式数据库多设备提交冲突场景,在给提交冲突做合并的过程中,如果多个设备同时修改了同一数据,则称这种场景为数据冲突。数据冲突采用默认冲突解决策略(Last-write-wins),基于提交时间戳,取时间戳较大的提交数据,当前不支持定制冲突解决策略。 - -### 数据库Schema化管理与谓词查询 - -单版本数据库支持在创建和打开数据库时指定Schema,数据库根据Schema定义感知KV记录的Value格式,以实现对Value值结构的检查,并基于Value中的字段实现索引建立和谓词查询。 - -### 分布式数据库备份能力 - - 提供分布式数据库备份能力,业务通过设置backup属性为true,可以触发分布式数据服务每日备份。当分布式数据库发生损坏,分布式数据服务会删除损坏数据库,并且从备份数据库中恢复上次备份的数据。如果不存在备份数据库,则创建一个新的数据库。同时支持加密数据库的备份能力。 - - -## 运作机制 - -分布式数据服务支撑OpenHarmony系统上应用程序数据库数据分布式管理,支持数据在相同帐号的多端设备之间相互同步,为用户在多端设备上提供一致的用户体验,分布式数据服务包含五部分: - -- **服务接口:** 分布式数据服务提供专门的数据库创建、数据访问、数据订阅等接口给应用程序调用,接口支持KV数据模型,支持常用的数据类型,同时确保接口的兼容性、易用性和可发布性。 - -- **服务组件:** 服务组件负责服务内元数据管理、权限管理、加密管理、备份和恢复管理以及多用户管理等、同时负责初始化底层分布式DB的存储组件、同步组件和通信适配层。 - -- **存储组件:** 存储组件负责数据的访问、数据的缩减、事务、快照、数据库加密,以及数据合并和冲突解决等特性。 - -- **同步组件:** 同步组件连结了存储组件与通信组件,其目标是保持在线设备间的数据库数据一致性,包括将本地产生的未同步数据同步给其他设备,接收来自其他设备发送过来的数据,并合并到本地设备中。 - -- **通信适配层:** 通信适配层负责调用底层公共通信层的接口完成通信管道的创建、连接,接收设备上下线消息,维护已连接和断开设备列表的元数据,同时将设备上下线信息发送给上层同步组件,同步组件维护连接的设备列表,同步数据时根据该列表,调用通信适配层的接口将数据封装并发送给连接的设备。 - -应用程序通过调用分布式数据服务接口实现分布式数据库创建、访问、订阅功能,服务接口通过操作服务组件提供的能力,将数据存储至存储组件,存储组件调用同步组件实现将数据同步,同步组件使用通信适配层将数据同步至远端设备,远端设备通过同步组件接收数据,并更新至本端存储组件,通过服务接口提供给应用程序使用。 - - -**图1** 数据分布式运作示意图 - - -![zh-cn_image_0000001183386164](figures/zh-cn_image_0000001183386164.png) - - -## 约束与限制 - -- 分布式数据服务的数据模型仅支持KV数据模型,不支持外键、触发器等关系型数据库中的功能。 - -- 分布式数据服务支持的KV数据模型规格: - - - 设备协同数据库,针对每条记录,Key的长度≤896 Byte,Value的长度<4 MB。 - - 单版本数据库,针对每条记录,Key的长度≤1 KB,Value的长度<4 MB。 - - 每个应用程序最多支持同时打开16个分布式数据库。 - -- 分布式数据库与本地数据库的使用场景不同,因此开发者应识别需要在设备间进行同步的数据,并将这些数据保存到分布式数据库中。 - -- 分布式数据服务当前不支持应用程序自定义冲突解决策略。 - -- 分布式数据服务针对每个应用程序当前的流控机制:KvStore的接口1秒最大访问1000次,1分钟最大访问10000次;KvManager的接口1秒最大访问50次,1分钟最大访问500次。 - -- 分布式数据库事件回调方法中不允许进行阻塞操作,例如修改UI组件。 diff --git a/zh-cn/application-dev/database/database-preference-guidelines.md b/zh-cn/application-dev/database/database-preference-guidelines.md deleted file mode 100644 index d72273651debe5978c25c5a5357ba83cf3f10ba9..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/database/database-preference-guidelines.md +++ /dev/null @@ -1,211 +0,0 @@ -# 首选项开发指导 - -> **说明:** -> -> 该功能特性从API Version 9开始支持。API Version 9之前可使用[轻量级存储](../reference/apis/js-apis-data-storage.md)的相关功能接口。 - -## 场景介绍 - -首选项功能通常用于保存应用的一些常用配置信息,并不适合需要存储大量数据和频繁改变数据的场景。应用的数据保存在文件中,这些文件可以持久化地存储在设备上。 - -需要注意的是,应用访问的实例包含文件所有数据,这些数据会一直加载在设备的内存中,直到应用主动从内存中将其移除前,应用都可以通过Preferences API进行相关数据操作。 - -## 接口说明 - -首选项为应用提供Key-Value键值型的文件数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。 - -数据存储形式为键值对,键的类型为字符串型,值的存储数据类型包括数字型、字符型、布尔型以及这3种类型的数组类型。 - -更多首选项相关接口,请见[首选项API](../reference/apis/js-apis-data-preferences.md)。 - -### 创建存储实例 - -读取指定文件,将数据加载到Preferences实例,即可创建一个存储实例,用于数据操作。 - -**表1** 首选项实例创建接口 - -| Bundle名称 | 接口名 | 描述 | -| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| ohos.data.preferences | getPreferences(context: Context, name: string): Promise\ | 读取指定首选项持久化文件,将数据加载到Preferences实例,用于数据操作。 | - -### 数据处理 - -通过put系列方法,可以增加或修改Preferences实例中的数据。 - -通过调用get系列方法,可以读取Preferences中的数据。 - -通过调用getAll系列方法,可以获取Preferences中包含所有键值的Object对象。 - -通过调用delete系列方法,可以删除Preferences中名为给定Key的存储键值对。 - -**表2** 首选项数据处理接口 - -| 类名 | 接口名 | 描述 | -| ----------- | ---------------------------------------------------------- | ------------------------------------------------------------ | -| Preferences | put(key: string, value: ValueType): Promise\ | 支持存入值为number、string、boolean、Array\、Array\、Array\类型的数据。 | -| Preferences | get(key: string, defValue: ValueType): Promise\ | 支持获取值为number、string、boolean、Array\、Array\、Array\类型的数据。 | -| Preferences | getAll(): Promise\ | 支持获取含有所有键值的Object对象。 | -| Preferences | delete(key: string): Promise\ | 支持从Preferences实例中删除名为给定Key的存储键值对。 | - - -### 数据持久化 - -通过执行flush方法,应用可以将缓存的数据再次写回文本文件中进行持久化存储。 - -**表4** 首选项持久化接口 - -| 类名 | 接口名 | 描述 | -| ----------- | ----------------------- | ------------------------------------------- | -| Preferences | flush(): Promise\ | 将Preferences实例通过异步线程回写入文件中。 | - -### 订阅数据变更 - -订阅数据变更,订阅的Key的值发生变更后,在执行flush方法后,会触发callback回调。 - -**表5** 首选项变化订阅接口 - -| 类名 | 接口名 | 描述 | -| ----------- | ------------------------------------------------------------ | -------------- | -| Preferences | on(type: 'change', callback: Callback<{ key : string }>): void | 订阅数据变更。 | -| Preferences | off(type: 'change', callback: Callback<{ key : string }>): void | 注销订阅。 | - -### 删除数据文件 - -通过调用以下两种接口,可以删除数据实例或对应的文件。 - -**表6** 首选项删除接口 - -| Bundle名称 | 接口名 | 描述 | -| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| ohos.data.preferences | deletePreferences(context: Context, name: string): Promise\ | 从缓存中移除已加载的Preferences对象,同时从设备上删除对应的文件。 | -| ohos.data.preferences | removePreferencesFromCache(context: Context, name: string): Promise\ | 仅从缓存中移除已加载的Preferences对象,主要用于释放内存。 | - -## 开发步骤 - -1. 准备工作,导入@ohos.data.preferences以及相关的模块到开发环境。 - - ```js - import data_preferences from '@ohos.data.preferences'; - ``` - -2. 获取Preferences实例。 - - 读取指定文件,将数据加载到Preferences实例,用于数据操作。 - - FA模型示例: - - ```js - // 获取context - import featureAbility from '@ohos.ability.featureAbility' - let context = featureAbility.getContext(); - - let preferences = null; - let promise = data_preferences.getPreferences(context, 'mystore'); - - promise.then((pref) => { - preferences = pref; - }).catch((err) => { - console.info("Failed to get preferences."); - }) - ``` - - Stage模型示例: - - ```ts - // 获取context - import UIAbility from '@ohos.app.ability.UIAbility'; - let preferences = null; - export default class EntryAbility extends UIAbility { - onWindowStageCreate(windowStage) { - let promise = data_preferences.getPreferences(this.context, 'mystore'); - promise.then((pref) => { - preferences = pref; - }).catch((err) => { - console.info("Failed to get preferences."); - }) - } - } - - - ``` - -3. 存入数据。 - - 使用put方法保存数据到缓存的实例中。 - - ```js - let putPromise = preferences.put('startup', 'auto'); - putPromise.then(() => { - console.info("Succeeded in putting the value of 'startup'."); - }).catch((err) => { - console.info("Failed to put the value of 'startup'. Cause: " + err); - }) - ``` - -4. 读取数据。 - - 使用get方法读取数据。 - - ```js - let getPromise = preferences.get('startup', 'default'); - getPromise.then((value) => { - console.info("The value of 'startup' is " + value); - }).catch((err) => { - console.info("Failed to get the value of 'startup'. Cause: " + err); - }) - ``` - -5. 数据持久化。 - - 应用存入数据到Preferences实例后,可以通过flush方法将Preferences实例回写到文件中。 - - ```js - preferences.flush(); - ``` - -6. 订阅数据变更。 - - 应用订阅数据变更需要指定observer作为回调方法。订阅的Key的值发生变更后,当执行flush方法时,observer被触发回调。 - - ```js - let observer = function (key) { - console.info("The key" + key + " changed."); - } - preferences.on('change', observer); - // 数据产生变更,由'auto'变为'manual' - preferences.put('startup', 'manual', function (err) { - if (err) { - console.info("Failed to put the value of 'startup'. Cause: " + err); - return; - } - console.info("Succeeded in putting the value of 'startup'."); - preferences.flush(function (err) { - if (err) { - console.info("Failed to flush. Cause: " + err); - return; - } - console.info("Succeeded in flushing."); // observer will be called. - }) - }) - ``` - -7. 删除指定文件。 - - 使用deletePreferences方法从内存中移除指定文件对应的Preferences单实例,并删除指定文件及其备份文件、损坏文件。删除指定文件时,应用不允许再使用该实例进行数据操作,否则会出现数据一致性问题。删除后,数据及文件将不可恢复。 - - ```js - let proDelete = data_preferences.deletePreferences(context, 'mystore'); - proDelete.then(() => { - console.info("Succeeded in deleting."); - }).catch((err) => { - console.info("Failed to delete. Cause: " + err); - }) - ``` - -## 相关实例 - -针对首选项开发,有以下相关实例可供参考: - -- [`Preferences`:首选项(ArkTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/DataManagement/Preferences) - -- [首选项(ArkTS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Data/Preferences) \ No newline at end of file diff --git a/zh-cn/application-dev/database/database-preference-overview.md b/zh-cn/application-dev/database/database-preference-overview.md deleted file mode 100644 index c2a904f521506eb67b1a2eebaba10753754ee5fe..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/database/database-preference-overview.md +++ /dev/null @@ -1,34 +0,0 @@ -# 首选项概述 - -首选项Preferences,适用于对`Key-Value`结构的数据进行存取和持久化操作。 - -应用获取某个`Preferences`对象后,该存储对象中的数据将会被缓存在内存中,以便应用获得更快的数据存取速度。 - -应用也可以将缓存的数据再次写回文本文件中进行持久化存储,由于文件读写将产生不可避免的系统资源开销,建议应用降低对持久化文件的读写频率。 - -关于数据库锁机制,开发者无需关注其具体实现。 - -## 基本概念 - -- **Key-Value数据结构** - - 一种键值型的数据结构。`Key`是不重复的关键字,`Value`是数据值。 - -- **非关系型数据库** - - 区别于关系数据库,不保证遵循ACID(Atomic、Consistency、Isolation及Durability)特性,不采用关系模型来组织数据,数据之间无关系。比如,以`Key-Value`数据结构组成的数据库。 - -## 运作机制 - -1. 应用通过指定首选项持久化文件将其中的数据加载到`Preferences`实例,系统会通过静态容器将该实例存储在内存中,同一应用或进程中每个文件仅存在一个`Preferences`实例,直到应用主动从内存中移除该实例或者删除该首选项持久化文件。 -2. 应用获取到首选项持久化文件对应的实例后,可以从`Preferences`实例中读取数据,或者将数据存入`Preferences`实例中。通过调用flush方法可以将`Preferences`实例中的数据回写到文件里。 - -**图1** 首选项运作机制 - -![zh-cn_image_0000001199139454](figures/zh-cn_image_0000001199139454.png) - -## 约束与限制 - -- 因`Preferences`实例会加载到内存中,建议存储的数据不超过一万条,并注意及时清理不再使用的实例,以便减少非内存开销。 -- 数据中的`Key`为`string`类型,要求非空且字符长度不超过80个字节。 -- 当数据中的`Value`为`string`类型时,允许为空,字符长度不超过8192个字节。 \ No newline at end of file diff --git a/zh-cn/application-dev/database/database-relational-guidelines.md b/zh-cn/application-dev/database/database-relational-guidelines.md deleted file mode 100644 index 5ab2e95815a2c2ca4465ebb4bdf7e1f87c8deef5..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/database/database-relational-guidelines.md +++ /dev/null @@ -1,505 +0,0 @@ -# 关系型数据库开发指导 - -## 场景介绍 - -关系型数据库是在SQLite基础上实现的本地数据操作机制,提供给用户无需编写原生SQL语句就能进行数据增删改查的方法,同时也支持原生SQL语句操作。 - - -## 接口说明 - -以下是关系型数据库的常用接口说明,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以Promise形式为例,更多接口及使用方式请见[关系型数据库](../reference/apis/js-apis-data-relationalStore.md)。 - -### 数据库的创建和删除 - -关系型数据库提供了数据库创建方式,以及对应的删除接口,涉及的API如下所示。 - -**表1** 数据库创建和删除API - -| 接口名 | 描述 | -| ------------------------------------------------------------ | ------------------------------------------------------------ | -| getRdbStore(context: Context, config: StoreConfig): Promise<RdbStore> | 获得一个相关的RdbStore,操作关系型数据库,用户可以根据自己的需求配置RdbStore的参数,然后通过RdbStore调用相关接口可以执行相关的数据操作,使用Promise异步回调。
-context:应用上下文。
-config:与此RDB存储相关的数据库配置。 | -| deleteRdbStore(context: Context, name: string): Promise<void> | 使用指定的数据库文件配置删除数据库,使用Promise异步回调。
-context:应用上下文。
-name:数据库名称。 | - -### 数据库的增删改查 - -关系型数据库提供对本地数据增删改查操作的能力,相关API如下所示。 - -- **新增** - - 关系型数据库提供了插入数据的接口,通过ValuesBucket输入要存储的数据,通过返回值判断是否插入成功,插入成功时返回最新插入数据所在的行号,失败时则返回-1。 - - **表2** 数据库插入API - - - | 类名 | 接口名 | 描述 | - | ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | - | RdbStore | insert(table: string, values: ValuesBucket): Promise<number> | 向目标表中插入一行数据,使用Promise异步回调。
如果操作成功,返回行ID;否则返回-1。
-table:指定的目标表名。
-values:表示要插入到表中的数据行。 | - -- **更新** - - 调用更新接口,传入要更新的数据,并通过RdbPredicates指定更新条件。该接口的返回值表示更新操作影响的行数。如果更新失败,则返回0。 - - **表3** 数据库更新API - - - | 类名 | 接口名 | 描述 | - | ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | - | RdbStore | update(values: ValuesBucket, predicates: RdbPredicates): Promise<number> | 根据RdbPredicates的指定实例对象更新数据库中的数据,使用Promise异步回调。
返回受影响的行数。
-values:以ValuesBucket存储的要更新的数据。
-predicates:表示RdbPredicates的实例对象指定的更新条件。 | - -- **删除** - - 调用删除接口,通过RdbPredicates指定删除条件。该接口的返回值表示删除的数据行数,可根据此值判断是否删除成功。如果删除失败,则返回0。 - - **表4** 数据库删除API - - - | 类名 | 接口名 | 描述 | - | ---------- | ---------------------------------------------------------- | ------------------------------------------------------------ | - | RdbStore | delete(predicates: RdbPredicates): Promise<number> | 根据RdbPredicates的指定实例对象从数据库中删除数据,使用Promise异步回调。
返回受影响的行数。
-predicates:RdbPredicates的实例对象指定的删除条件。 | - -- **查询** - - 关系型数据库提供了两种查询数据的方式: - - - 直接调用查询接口。使用该接口,会将包含查询条件的谓词自动拼接成完整的SQL语句进行查询操作,无需用户传入原生的SQL语句。 - - 执行原生的SQL语句进行查询操作。 - - **表5** 数据库查询API - - | 类名 | 接口名 | 描述 | - | ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | - | RdbStore | query(predicates: RdbPredicates, columns?: Array<string>): Promise<ResultSet> | 根据指定条件查询数据库中的数据,使用Promise异步回调。
-predicates:表示RdbPredicates的实例对象指定的查询条件。
-columns:表示要查询的列。如果值为空,则查询应用于所有列。 | - | RdbStore | querySql(sql: string, bindArgs?: Array<ValueType>): Promise<ResultSet> | 根据指定SQL语句查询数据库中的数据,使用Promise异步回调。
-sql:指定要查询的SQL语句。
-bindArgs:SQL语句中参数的值。 | - | RdbStore | remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array<string>): Promise<ResultSet> | 根据指定条件查询指定远程设备数据库中的数据。使用Promise异步回调。
-device:指定远程查询的设备networkId。
-table:指定远程查询的表名。
-predicates:表示RdbPredicates的实例对象,指定查询的条件。
-columns:表示要查询的列。如果值为空,则查询应用于所有列。 | - -### 数据库谓词的使用 - -关系型数据库提供了用于设置数据库操作条件的谓词RdbPredicates,该类确定RDB中条件表达式的值是true还是false。 - -以下列举几个常用谓词,更多谓词的使用请见[关系型数据库谓词](../reference/apis/js-apis-data-relationalStore.md#rdbpredicates)。 - -**表6** 数据库谓词API - -| 类名 | 接口名 | 描述 | -| --------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbPredicates | equalTo(field: string, value: ValueType): RdbPredicates | 配置谓词以匹配数据字段为ValueType且值等于指定值的字段。
-field:数据库表中的列名。
-value:指示要与谓词匹配的值。
-RdbPredicates:返回与指定字段匹配的谓词。 | -| RdbPredicates | notEqualTo(field: string, value: ValueType): RdbPredicates | 配置谓词以匹配数据字段为ValueType且值不等于指定值的字段。
-field:数据库表中的列名。
-value:指示要与谓词匹配的值。
-RdbPredicates:返回与指定字段匹配的谓词。 | -| RdbPredicates | or(): RdbPredicates | 将或条件添加到谓词中。
-RdbPredicates:返回带有或条件的谓词。 | -| RdbPredicates | and(): RdbPredicates | 向谓词添加和条件。
-RdbPredicates:返回带有和条件的谓词。 | -| RdbPredicates | contains(field: string, value: string): RdbPredicates | 配置谓词以匹配数据字段为String且value包含指定值的字段。
-field:数据库表中的列名。
-value:指示要与谓词匹配的值。
-RdbPredicates:返回带有包含条件的谓词。 | - - -### 查询结果集的使用 - -关系型数据库提供了查询返回的结果集ResultSet,其指向查询结果中的一行数据,供用户对查询结果进行遍历和访问。 - -更多结果集的接口使用,请见[结果集](../reference/apis/js-apis-data-relationalStore.md#resultset)。 - -> **须知:** -> **结果集使用完后,请一定要调用close方法显式关闭。** - -**表7** 结果集API - -| 类名 | 接口名 | 描述 | -| ----------- | ---------------------------------------- | ------------------------------------------ | -| 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 | 关闭结果集。 | - - - -### 设置分布式列表 - -> **说明:** -> -> - 在使用RdbStore的setDistributedTables、obtainDistributedTableName、sync、on、off接口时,需要请求相应的权限:ohos.permission.DISTRIBUTED_DATASYNC。 -> - 使用分布式列表前,需要先建立设备间组网,具体接口及使用可见[设备管理](../reference/apis/js-apis-device-manager.md)。 - -**设置分布式列表** - -**表8** 设置分布式列表 - -| 类名 | 接口名 | 描述 | -| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbStore | setDistributedTables(tables: Array\): Promise\ | 设置分布式列表,使用Promise异步回调。
-tables:要设置的分布式列表表名。 | - -**根据本地表名获取指定远程设备的分布式表名** - -用户根据本地表名获取指定远程设备的分布式表名。在查询远程设备数据库时,需要使用分布式表名。 - -**表9** 根据本地表名获取指定远程设备的分布式表名 - -| 类名 | 接口名 | 描述 | -| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbStore | obtainDistributedTableName(device: string, table: string): Promise\ | 根据本地表名获取指定远程设备的分布式表名。在查询远程设备数据库时,需要使用分布式表名,使用Promise异步回调。
-device:远程设备。
-table:本地表名。 | - -**在设备之间同步数据** - -**表10** 在设备之间同步数据 - -| 类名 | 接口名 | 描述 | -| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbStore | sync(mode: SyncMode, predicates: RdbPredicates): Promise\> | 在设备之间同步数据,使用Promise异步回调。
-mode:指同步模式。SYNC_MODE_PUSH 表示数据从本地设备推送到远程设备;SYNC_MODE_PULL 表示数据从远程设备拉至本地设备。
-predicates:约束同步数据和设备。
-string:设备ID;number:每个设备同步状态,0表示成功,其他值表示失败。 | - -**注册数据库的观察者** - -**表11** 注册数据库的观察者 - -| 类名 | 接口名 | 描述 | -| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbStore | on(event: 'dataChange', type: SubscribeType, observer: Callback\>): void | 注册数据库的观察者。当分布式数据库中的数据发生更改时,将调用回调。
-type:订阅类型;SUBSCRIBE_TYPE_REMOTE 订阅远程数据更改。
-observer:指分布式数据库中数据更改事件的观察者。 | - -**从数据库中删除指定类型的指定观察者** - -**表12** 从数据库中删除指定类型的指定观察者 - -| 类名 | 接口名 | 描述 | -| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| RdbStore | off(event:'dataChange', type: SubscribeType, observer: Callback\>): void; | 从数据库中删除指定类型的指定观察者,使用callback异步回调。
-type:订阅类型;SUBSCRIBE_TYPE_REMOTE 订阅远程数据更改。
-observer:指已注册的数据更改观察者。 | - -### 数据库的备份和恢复 - -**备份** - -**表13** 备份数据库 - -| 类名 | 接口名 | 描述 | -| ---------- | --------------------------------------------- | ------------------------------------------------------------ | -| RdbStore | backup(destName: string): Promise<void> | 以指定名称备份数据库,使用Promise异步回调。
-destName:指定数据库的备份文件名。 | - -**恢复** - -**表14** 恢复数据库 - -| 类名 | 接口名 | 描述 | -| ---------- | --------------------------------------------- | ------------------------------------------------------------ | -| RdbStore | restore(srcName: string): Promise<void> | 从指定的数据库备份文件恢复数据库,使用Promise异步回调。
-srcName:指定数据库的备份文件名。 | - -### 事务 - -**表15** 事务 - -| 类名 | 接口名 | 描述 | -| -------- | ----------------------- | --------------------------------- | -| RdbStore | beginTransaction(): void | 在开始执行SQL语句之前,开始事务。 | -| RdbStore | commit(): void | 提交已执行的SQL语句。 | -| RdbStore | rollBack(): void | 回滚已经执行的SQL语句。 | - -## 开发步骤 - -1. 创建数据库。 - - (1) 配置数据库相关信息,包括数据库的名称、存储模式、是否为只读模式等。 - - (2) 初始化数据库表结构和相关数据。 - - (3) 创建数据库。 - - FA模型示例: - - ```js - import relationalStore from '@ohos.data.relationalStore' - import featureAbility from '@ohos.ability.featureAbility' - - var store; - - // 获取context - let context = featureAbility.getContext(); - - const STORE_CONFIG = { - name: "RdbTest.db", - securityLevel: relationalStore.SecurityLevel.S1 - }; - - // 假设当前数据库版本为3 - relationalStore.getRdbStore(context, STORE_CONFIG, function (err, rdbStore) { - store = rdbStore; - // 当数据库创建时,数据库默认版本为0 - if (store.version == 0) { - store.executeSql("CREATE TABLE IF NOT EXISTS student (id INTEGER PRIMARY KEY AUTOINCREMENT, score REAL);", null); - // 设置数据库的版本,入参为大于0的整数 - store.version = 3; - } - - // 当数据库存在并假定版本为1时,例应用从某一版本升级到当前版本,数据库需要从1版本升级到2版本 - if (store.version != 3 && store.version == 1) { - // version = 1:表结构:student (id, age) => version = 2:表结构:student (id, age, score) - store.executeSql("ALTER TABLE student ADD COLUMN score REAL", null); - store.version = 2; - } - - // 当数据库存在并假定版本为2时,例应用从某一版本升级到当前版本,数据库需要从2版本升级到3版本 - if (store.version != 3 && store.version == 2) { - // version = 2:表结构:student (id, age, score) => version = 3:表结构:student (id, score) - store.executeSql("ALTER TABLE student DROP COLUMN age INTEGER", null); - store.version = 3; - } - }) - ``` - Stage模型示例: - ```ts - import relationalStore from '@ohos.data.relationalStore' - import UIAbility from '@ohos.app.ability.UIAbility' - - class EntryAbility extends UIAbility { - onWindowStageCreate(windowStage) { - var store; - const STORE_CONFIG = { - name: "RdbTest.db", - securityLevel: relationalStore.SecurityLevel.S1 - }; - - // 假设当前数据库版本为3 - relationalStore.getRdbStore(this.context, STORE_CONFIG, function (err, rdbStore) { - store = rdbStore; - // 当数据库创建时,数据库默认版本为0 - if (store.version == 0) { - store.executeSql("CREATE TABLE IF NOT EXISTS student (id INTEGER PRIMARY KEY AUTOINCREMENT, score REAL);", null); - // 设置数据库的版本,入参为大于0的整数 - store.version = 3; - } - - // 当数据库存在并假定版本为1时,例应用从某一版本升级到当前版本,数据库需要从1版本升级到2版本 - if (store.version != 3 && store.version == 1) { - // version = 1:表结构:student (id, age) => version = 2:表结构:student (id, age, score) - store.executeSql("ALTER TABLE student ADD COLUMN score REAL", null); - store.version = 2; - } - - // 当数据库存在并假定版本为2时,例应用从某一版本升级到当前版本,数据库需要从2版本升级到3版本 - if (store.version != 3 && store.version == 2) { - // version = 2:表结构:student (id, age, score) => version = 3:表结构:student (id, score) - store.executeSql("ALTER TABLE student DROP COLUMN age INTEGER", null); - store.version = 3; - } - }) - } - } - ``` - -2. 插入数据。 - - (1) 构造要插入的数据,以ValuesBucket形式存储。 - - (2) 调用关系型数据库提供的插入接口。 - - 示例代码如下: - - ```js - let u8 = new Uint8Array([1, 2, 3]); - const valueBucket = { "name": "Tom", "age": 18, "salary": 100.5, "blobType": u8 }; - let insertPromise = store.insert("test", valueBucket); - ``` - - ```js - //使用事务插入数据 - try { - store.beginTransaction(); - let u8 = new Uint8Array([1, 2, 3]); - const valueBucket = { "name": "Tom", "age": 18, "salary": 100.5, "blobType": u8 }; - let promise = store.insert("test", valueBucket); - promise.then(() => { - store.commit(); - }) - } catch (err) { - console.error(`Transaction failed, err: ${err}`); - store.rollBack(); - } - ``` - -3. 查询数据。 - - (1) 构造用于查询的谓词对象,设置查询条件。 - - (2) 调用查询接口查询数据。 - - (3) 调用结果集接口,返回查询结果。 - - 示例代码如下: - - ```js - let predicates = new relationalStore.RdbPredicates("test"); - predicates.equalTo("name", "Tom"); - let promisequery = store.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(); - }) - ``` - -4. 设置分布式同步表。 - - (1) 权限配置文件中增加以下配置。 - - ```json - "requestPermissions": - { - "name": "ohos.permission.DISTRIBUTED_DATASYNC" - } - ``` - - (2) 获取应用权限。 - - (3) 数据库调用接口设置分布式同步列表。 - - (4) 判断是否设置成功。 - - 示例代码如下: - - ```js - let context = featureAbility.getContext(); - context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) { - console.info(`result.requestCode=${result.requestCode}`); - }) - let promise = store.setDistributedTables(["test"]); - promise.then(() => { - console.info(`setDistributedTables success.`); - }).catch((err) => { - console.error(`setDistributedTables failed, ${err}`); - }) - ``` - -5. 分布式数据同步。 - - (1) 构造用于同步分布式表的谓词对象,指定组网内的远程设备。 - - (2) 调用同步数据的接口。 - - (3) 判断数据同步是否成功。 - - 示例代码如下: - - ```js - let predicate = new relationalStore.RdbPredicates('test'); - predicate.inDevices(['12345678abcde']); - let promise = store.sync(relationalStore.SyncMode.SYNC_MODE_PUSH, predicate); - promise.then((result) => { - console.info(`sync done.`); - for (let i = 0; i < result.length; i++) { - console.info(`device=${result[i][0]}, status=${result[i][1]}`); - } - }).catch((err) => { - console.error(`sync failed, err: ${err}`); - }) - ``` - -6. 分布式数据订阅。 - - (1) 调用分布式数据订阅接口,注册数据库的观察者。 - - (2) 当分布式数据库中的数据发生更改时,将调用回调。 - - 示例代码如下: - - ```js - function storeObserver(devices) { - for (let i = 0; i < devices.length; i++) { - console.info(`device= ${devices[i]} data changed`); - } - } - - try { - store.on('dataChange', relationalStore.SubscribeType.SUBSCRIBE_TYPE_REMOTE, storeObserver); - } catch (err) { - console.error(`register observer failed, err: ${err}`); - } - ``` - -7. 跨设备查询。 - - (1) 根据本地表名获取指定远程设备的分布式表名。 - - (2) 调用结果集接口,返回查询结果。 - - 示例代码如下: - - ```js - import deviceManager from '@ohos.distributedHardware.deviceManager' - - let deviceIds = []; - deviceManager.createDeviceManager('bundleName', (err, value) => { - if (!err) { - let devManager = value; - if (devManager != null) { - // 获取deviceIds - let devices = devManager.getTrustedDeviceListSync(); - for (let i = 0; i < devices.length; i++) { - deviceIds[i] = devices[i].deviceId; - } - } - } - }) - - let tableName = store.obtainDistributedTableName(deviceIds[0], "test"); - let resultSet = store.querySql("SELECT * FROM " + tableName); - ``` - -8. 远程查询。 - - (1) 构造用于查询分布式表的谓词对象,指定组网内的远程分布式表名和设备。 - - (2) 调用结果集接口,返回查询结果。 - - 示例代码如下: - - ```js - let rdbPredicate = new relationalStore.RdbPredicates('employee'); - predicates.greaterThan("id", 0) ; - let promiseQuery = store.remoteQuery('12345678abcde', 'employee', rdbPredicate); - promiseQuery.then((resultSet) => { - while (resultSet.goToNextRow()) { - let idx = resultSet.getLong(0); - let name = resultSet.getString(1); - let age = resultSet.getLong(2); - console.info(`indx: ${idx}, name: ${name}, age: ${age}`); - } - resultSet.close(); - }).catch((err) => { - console.error(`failed to remoteQuery, err: ${err}`); - }) - ``` - -9. 数据库的备份和恢复。 - - (1) 调用数据库的备份接口,备份当前数据库文件。 - - 示例代码如下: - - ```js - let promiseBackup = store.backup("dbBackup.db"); - promiseBackup.then(() => { - console.info(`Backup success.`); - }).catch((err) => { - console.error(`Backup failed, err: ${err}`); - }) - ``` - - (2) 调用数据库的恢复接口,从数据库的备份文件恢复数据库文件。 - - 示例代码如下: - - ```js - let promiseRestore = store.restore("dbBackup.db"); - promiseRestore.then(() => { - console.info(`Restore success.`); - }).catch((err) => { - console.error(`Restore failed, err: ${err}`); - }) - ``` - -## 相关实例 -针对关系型数据库开发,有以下相关实例可供参考: - -- [`DistributedRdb`:分布式关系型数据库(ArkTS)(API9)(Full SDK)](https://gitee.com/openharmony/applications_app_samples/tree/master/code/SuperFeature/DistributedAppDev/DistributedRdb) - -- [关系型数据库(JS)(API8)](https://gitee.com/openharmony/codelabs/tree/master/Data/JSRelationshipData) - -- [关系型数据库(ArkS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Data/Rdb) \ No newline at end of file diff --git a/zh-cn/application-dev/database/database-relational-overview.md b/zh-cn/application-dev/database/database-relational-overview.md deleted file mode 100644 index cba72e0085f71da57bebecff8d39475e6751970e..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/database/database-relational-overview.md +++ /dev/null @@ -1,43 +0,0 @@ -# 关系型数据库概述 - -关系型数据库(Relational Database,RDB)是一种基于关系模型来管理数据的数据库。关系型数据库基于SQLite组件提供了一套完整的对本地数据库进行管理的机制,对外提供了一系列的增、删、改、查等接口,也可以直接运行用户输入的SQL语句来满足复杂的场景需要。当应用卸载后,其相关数据库会被自动清除。 - -关于数据库锁机制,开发者无需关注其具体实现。 - -## 基本概念 - -- **关系型数据库** - - 基于关系模型来管理数据的数据库,以行和列的形式存储数据。 - -- **谓词** - - 数据库中用来代表数据实体的性质、特征或者数据实体之间关系的词项,主要用来定义数据库的操作条件。 - -- **结果集** - - 指用户查询之后的结果集合,可以对数据进行访问。结果集提供了灵活的数据访问方式,可以更方便的拿到用户想要的数据。 - -- **SQLite数据库** - - 一款遵守ACID的轻型开源关系型数据库管理系统。 - -## 运作机制 - -关系型数据库对外提供通用的操作接口,底层使用SQLite作为持久化存储引擎,支持SQLite具有的所有数据库特性,包括但不限于事务、索引、视图、触发器、外键、参数化查询和预编译SQL语句。 - -**图1** 关系型数据库运作机制 - -![how-rdb-works](figures/how-rdb-works.png) - -## 默认配置 - -- 系统默认日志方式是WAL(Write Ahead Log)模式。 -- 系统默认落盘方式是FULL模式。 -- OpenHarmony数据库使用的共享内存默认大小是2MB。 - -## 约束与限制 - -- 数据库中连接池的最大数量是4个,用以管理用户的读操作。 - -- 为保证数据的准确性,数据库同一时间只能支持一个写操作。 \ No newline at end of file diff --git a/zh-cn/application-dev/database/figures/dataManagement.jpg b/zh-cn/application-dev/database/figures/dataManagement.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ba50f39146ba7a40e444f6dfb7e6a106d2c5502e Binary files /dev/null and b/zh-cn/application-dev/database/figures/dataManagement.jpg differ diff --git a/zh-cn/application-dev/database/figures/dataShare.jpg b/zh-cn/application-dev/database/figures/dataShare.jpg new file mode 100644 index 0000000000000000000000000000000000000000..48546f9aaa05c62839308867ce633834175a55fc Binary files /dev/null and b/zh-cn/application-dev/database/figures/dataShare.jpg differ diff --git a/zh-cn/application-dev/database/figures/deviceKVStore.jpg b/zh-cn/application-dev/database/figures/deviceKVStore.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9932b929f0f0d4c5103e614835a051fca66ecc88 Binary files /dev/null and b/zh-cn/application-dev/database/figures/deviceKVStore.jpg differ diff --git a/zh-cn/application-dev/database/figures/distributedObject.jpg b/zh-cn/application-dev/database/figures/distributedObject.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4f3eaa3f619a3a80a9c6df409325d405598369c5 Binary files /dev/null and b/zh-cn/application-dev/database/figures/distributedObject.jpg differ diff --git a/zh-cn/application-dev/database/figures/distributedObject_sync.jpg b/zh-cn/application-dev/database/figures/distributedObject_sync.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f88e727ae922a8bb1f4b6f5189c373be2d7457ab Binary files /dev/null and b/zh-cn/application-dev/database/figures/distributedObject_sync.jpg differ diff --git a/zh-cn/application-dev/database/figures/distributedObject_syncView.jpg b/zh-cn/application-dev/database/figures/distributedObject_syncView.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e190a47cd102b646631818b708887ec81da6b40c Binary files /dev/null and b/zh-cn/application-dev/database/figures/distributedObject_syncView.jpg differ diff --git a/zh-cn/application-dev/database/figures/how-distributedobject-works.png b/zh-cn/application-dev/database/figures/how-distributedobject-works.png deleted file mode 100644 index 9af60f511701f7ef7e8424492d42f247c6088b28..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/database/figures/how-distributedobject-works.png and /dev/null differ diff --git a/zh-cn/application-dev/database/figures/how-rdb-works.png b/zh-cn/application-dev/database/figures/how-rdb-works.png deleted file mode 100644 index e85411eef39281e3213d6b4697a8d32d2cecd9a2..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/database/figures/how-rdb-works.png and /dev/null differ diff --git a/zh-cn/application-dev/database/figures/kvStore.jpg b/zh-cn/application-dev/database/figures/kvStore.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ca3fa9d870263c129eaaa42b5ac173122ab3bb44 Binary files /dev/null and b/zh-cn/application-dev/database/figures/kvStore.jpg differ diff --git a/zh-cn/application-dev/database/figures/kvStore_development_process.png b/zh-cn/application-dev/database/figures/kvStore_development_process.png new file mode 100644 index 0000000000000000000000000000000000000000..0ff7312c572ee2fdc2c9b3db6aab4f999331f29e Binary files /dev/null and b/zh-cn/application-dev/database/figures/kvStore_development_process.png differ diff --git a/zh-cn/application-dev/database/figures/preferences.jpg b/zh-cn/application-dev/database/figures/preferences.jpg new file mode 100644 index 0000000000000000000000000000000000000000..578c170e4e8a1ed25d7698c5860ffdb25c245c37 Binary files /dev/null and b/zh-cn/application-dev/database/figures/preferences.jpg differ diff --git a/zh-cn/application-dev/database/figures/relationStore_local.jpg b/zh-cn/application-dev/database/figures/relationStore_local.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c6b69c19565a7c7b05b57eb5a3cf303d05c82d0e Binary files /dev/null and b/zh-cn/application-dev/database/figures/relationStore_local.jpg differ diff --git a/zh-cn/application-dev/database/figures/relationalStore_sync.jpg b/zh-cn/application-dev/database/figures/relationalStore_sync.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac24ed5e62fcdfa22a927cdbd64138590047f967 Binary files /dev/null and b/zh-cn/application-dev/database/figures/relationalStore_sync.jpg differ diff --git a/zh-cn/application-dev/database/figures/silent_dataShare.jpg b/zh-cn/application-dev/database/figures/silent_dataShare.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a0578593de2bcf0eecd163481a882e58b1c4d138 Binary files /dev/null and b/zh-cn/application-dev/database/figures/silent_dataShare.jpg differ diff --git a/zh-cn/application-dev/database/figures/singleKVStore.jpg b/zh-cn/application-dev/database/figures/singleKVStore.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3cf40e1b9d866b638eafc414f51b9a0a9459c12 Binary files /dev/null and b/zh-cn/application-dev/database/figures/singleKVStore.jpg differ diff --git a/zh-cn/application-dev/database/figures/zh-cn_DataShare.png b/zh-cn/application-dev/database/figures/zh-cn_DataShare.png deleted file mode 100644 index b7ea19a7a70dd5aeefc31d59cbccf1fdab5a8200..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/database/figures/zh-cn_DataShare.png and /dev/null differ diff --git a/zh-cn/application-dev/database/figures/zh-cn_image_0000001183386164.png b/zh-cn/application-dev/database/figures/zh-cn_image_0000001183386164.png deleted file mode 100644 index 0538c11963b2e54fccc57d560831d41ceab82446..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/database/figures/zh-cn_image_0000001183386164.png and /dev/null differ diff --git a/zh-cn/application-dev/database/figures/zh-cn_image_0000001199139454.png b/zh-cn/application-dev/database/figures/zh-cn_image_0000001199139454.png deleted file mode 100644 index 6c41abd0be236566acb9ce45ee20de57f0b1e6c8..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/database/figures/zh-cn_image_0000001199139454.png and /dev/null differ diff --git a/zh-cn/application-dev/database/figures/zh-cn_image_0000001542496993.png b/zh-cn/application-dev/database/figures/zh-cn_image_0000001542496993.png new file mode 100644 index 0000000000000000000000000000000000000000..de0fa2afbd5c9301700618436126ca60e2666a06 Binary files /dev/null and b/zh-cn/application-dev/database/figures/zh-cn_image_0000001542496993.png differ diff --git a/zh-cn/application-dev/database/public_sys-resources/icon-caution.gif b/zh-cn/application-dev/database/public_sys-resources/icon-caution.gif deleted file mode 100644 index 6e90d7cfc2193e39e10bb58c38d01a23f045d571..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/database/public_sys-resources/icon-caution.gif and /dev/null differ diff --git a/zh-cn/application-dev/database/public_sys-resources/icon-danger.gif b/zh-cn/application-dev/database/public_sys-resources/icon-danger.gif deleted file mode 100644 index 6e90d7cfc2193e39e10bb58c38d01a23f045d571..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/database/public_sys-resources/icon-danger.gif and /dev/null differ diff --git a/zh-cn/application-dev/database/public_sys-resources/icon-note.gif b/zh-cn/application-dev/database/public_sys-resources/icon-note.gif deleted file mode 100644 index 6314297e45c1de184204098efd4814d6dc8b1cda..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/database/public_sys-resources/icon-note.gif and /dev/null differ diff --git a/zh-cn/application-dev/database/public_sys-resources/icon-notice.gif b/zh-cn/application-dev/database/public_sys-resources/icon-notice.gif deleted file mode 100644 index 86024f61b691400bea99e5b1f506d9d9aef36e27..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/database/public_sys-resources/icon-notice.gif and /dev/null differ diff --git a/zh-cn/application-dev/database/public_sys-resources/icon-tip.gif b/zh-cn/application-dev/database/public_sys-resources/icon-tip.gif deleted file mode 100644 index 93aa72053b510e456b149f36a0972703ea9999b7..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/database/public_sys-resources/icon-tip.gif and /dev/null differ diff --git a/zh-cn/application-dev/database/public_sys-resources/icon-warning.gif b/zh-cn/application-dev/database/public_sys-resources/icon-warning.gif deleted file mode 100644 index 6e90d7cfc2193e39e10bb58c38d01a23f045d571..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/database/public_sys-resources/icon-warning.gif and /dev/null differ diff --git a/zh-cn/application-dev/database/share-data-by-datashareextensionability.md b/zh-cn/application-dev/database/share-data-by-datashareextensionability.md new file mode 100644 index 0000000000000000000000000000000000000000..78c77bc77393877a4a73fe8fdfc90d72c27b05a3 --- /dev/null +++ b/zh-cn/application-dev/database/share-data-by-datashareextensionability.md @@ -0,0 +1,213 @@ +# 通过DataShareExtensionAbility实现数据共享 + + +## 场景介绍 + +跨应用访问数据时,可以通过DataShareExtensionAbility拉起数据提供方的应用以实现对数据的访问。 + +此种方式支持跨应用拉起数据提供方的DataShareExtension,数据提供方的开发者可以在回调中实现灵活的业务逻辑。用于跨应用复杂业务场景。 + + +## 运作机制 + +数据共享可分为数据的提供方和访问方两部分。 + +- 数据提供方:[DataShareExtensionAbility](../reference/apis/js-apis-application-dataShareExtensionAbility.md),可以选择性实现数据的增、删、改、查,以及文件打开等功能,并对外共享这些数据。 + +- 数据访问方:由[createDataShareHelper()](../reference/apis/js-apis-data-dataShare.md/#datasharecreatedatasharehelper)方法所创建的工具类,利用工具类,便可以访问提供方提供的这些数据。 + +**图1** 数据共享运作机制   + +![dataShare](figures/dataShare.jpg) + +- DataShareExtensionAbility模块为数据提供方,实现跨应用数据共享的相关业务。 + +- DataShareHelper模块为数据访问方,提供各种访问数据的接口,包括增删改查等。 + +- 数据访问方与提供方通过IPC进行通信,数据提供方可以通过数据库实现,也可以通过其他数据存储方式实现。 + +- ResultSet模块通过共享内存实现,用于存储查询数据得到的结果集,并提供了遍历结果集的方法。 + + +## 实现说明 + + +### 数据提供方应用的开发(仅限系统应用) + +[DataShareExtensionAbility](../reference/apis/js-apis-application-dataShareExtensionAbility.md)提供以下API,根据需要重写对应回调方法。 + +- **onCreate**:DataShare客户端连接DataShareExtensionAbility服务端时,服务端需要在此回调中实现初始化业务逻辑,该方法可以选择性重写。 + +- **insert**:业务函数,客户端请求插入数据时回调此接口,服务端需要在此回调中实现插入数据功能,该方法可以选择性重写。 + +- **update**:业务函数,客户端请求更新数据时回调此接口,服务端需要在此回调中实现更新数据功能,该方法可以选择性重写。 + +- **delete**:业务函数,客户端请求删除数据时回调此接口,服务端需要在此回调中实现删除数据功能,该方法可以选择性重写。 + +- **query**:业务函数,客户端请求查询数据时回调此接口,服务端需要在此回调中实现查询数据功能,该方法可以选择性重写。 + +- **batchInsert**:业务函数,客户端请求批量插入数据时回调此接口,服务端需要在此回调中实现批量插入数据的功能,该方法可以选择性重写。 + +- **normalizeUri**:业务函数,客户端给定的URI转换为服务端使用的URI时回调此接口,该方法可以选择性重写。 + +- **denormalizeUri**:业务函数,服务端使用的URI转换为客户端传入的初始URI时服务端回调此接口,该方法可以选择性重写。 + +开发者在实现一个数据共享服务时,需要在DevEco Studio工程中手动新建一个DataShareExtensionAbility,具体步骤如下。 + +1. 在工程Module对应的ets目录下,右键选择“New > Directory”,新建一个目录并命名为DataShareExtAbility。 + +2. 在DataShareAbility目录,右键选择“New > TypeScript File”,新建一个TypeScript文件并命名为DataShareExtAbility.ts。 + +3. 在DataShareExtAbility.ts文件中,导入 +`@ohos.application.DataShareExtensionAbility`模块,开发者可根据应用需求选择性重写其业务实现。例如数据提供方只提供插入、删除和查询服务,则可只重写这些接口,并导入对应的基础依赖模块。 + + ```js + import Extension from '@ohos.application.DataShareExtensionAbility'; + import rdb from '@ohos.data.relationalStore'; + import dataSharePredicates from '@ohos.data.dataSharePredicates'; + ``` + +4. 数据提供方的业务实现由开发者自定义。例如可以通过数据库、读写文件或访问网络等各方式实现数据提供方的数据存储。 + + ```js + const DB_NAME = 'DB00.db'; + const TBL_NAME = 'TBL00'; + const DDL_TBL_CREATE = "CREATE TABLE IF NOT EXISTS " + + TBL_NAME + + ' (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, isStudent BOOLEAN, Binary BINARY)'; + + let rdbStore; + let result; + + export default class DataShareExtAbility extends Extension { + private rdbStore_; + + // 重写onCreate接口 + onCreate(want, callback) { + result = this.context.cacheDir + '/datashare.txt'; + // 业务实现使用RDB + rdb.getRdbStore(this.context, { + name: DB_NAME, + securityLevel: rdb.SecurityLevel.S1 + }, function (err, data) { + rdbStore = data; + rdbStore.executeSql(DDL_TBL_CREATE, [], (err) => { + console.info(`DataShareExtAbility onCreate, executeSql done err:${err}`); + }); + if (callback) { + callback(); + } + }); + } + + // 重写query接口 + query(uri, predicates, columns, callback) { + if (predicates === null || predicates === undefined) { + console.info('invalid predicates'); + } + try { + rdbStore.query(TBL_NAME, predicates, columns, (err, resultSet) => { + if (resultSet !== undefined) { + console.info(`resultSet.rowCount:${resultSet.rowCount}`); + } + if (callback !== undefined) { + callback(err, resultSet); + } + }); + } catch (err) { + console.error(`Failed to query. Code:${err.code},message:${err.message}`); + } + } + // 可根据应用需求,选择性重写各个接口 + }; + ``` + +5. 在module.json5中定义DataShareExtensionAbility。 + + **表1** module.json5对应属性字段 + + | 属性名称 | 备注说明 | 必填 | + | -------- | -------- | -------- | + | name | Ability名称,对应Ability派生的ExtensionAbility类名。 | 是 | + | type | Ability类型,DataShare对应的Ability类型为“dataShare”,表示基于datashare模板开发的。 | 是 | + | uri | 通信使用的URI,是客户端链接服务端的唯一标识。 | 是 | + | exported | 对其他应用是否可见,设置为true时,才能与其他应用进行通信传输数据。 | 是 | + | readPermission | 访问数据时需要的权限,不配置默认不进行读权限校验。 | 否 | + | writePermission | 修改数据时需要的权限,不配置默认不进行写权限校验。 | 否 | + + **module.json5配置样例:** + + + ```json + "extensionAbilities": [ + { + "srcEntrance": "./ets/DataShareExtAbility/DataShareExtAbility.ts", + "name": "DataShareExtAbility", + "icon": "$media:icon", + "description": "$string:description_datashareextability", + "type": "dataShare", + "uri": "datashare://com.samples.datasharetest.DataShare", + "exported": true + } + ] + ``` + + +### 数据访问方应用的开发 + +1. 导入基础依赖包。 + + ```js + import UIAbility from '@ohos.app.ability.UIAbility'; + import dataShare from '@ohos.data.dataShare'; + import dataSharePredicates from '@ohos.data.dataSharePredicates'; + ``` + +2. 定义与数据提供方通信的URI字符串。 + + ```js + // 作为参数传递的URI,与module.json5中定义的URI的区别是多了一个"/",是因为作为参数传递的URI中,在第二个与第三个"/"中间,存在一个DeviceID的参数 + let dseUri = ('datashare:///com.samples.datasharetest.DataShare'); + ``` + +3. 创建工具接口类对象。 + + ```js + let dsHelper; + let abilityContext; + + export default class EntryAbility extends UIAbility { + onWindowStageCreate(windowStage) { + abilityContext = this.context; + dataShare.createDataShareHelper(abilityContext, dseUri, (err, data) => { + dsHelper = data; + }); + } + } + ``` + +4. 获取到接口类对象后,便可利用其提供的接口访问提供方提供的服务,如进行数据的增删改查等。 + + ```js + // 构建一条数据 + let valuesBucket = { 'name': 'ZhangSan', 'age': 21, 'isStudent': false, 'Binary': new Uint8Array([1, 2, 3]) }; + let updateBucket = { 'name': 'LiSi', 'age': 18, 'isStudent': true, 'Binary': new Uint8Array([1, 2, 3]) }; + let predicates = new dataSharePredicates.DataSharePredicates(); + let valArray = ['*']; + // 插入一条数据 + dsHelper.insert(dseUri, valuesBucket, (err, data) => { + console.info(`dsHelper insert result:${data}`); + }); + // 更新数据 + dsHelper.update(dseUri, predicates, updateBucket, (err, data) => { + console.info(`dsHelper update result:${data}`); + }); + // 查询数据 + dsHelper.query(dseUri, predicates, valArray, (err, data) => { + console.info(`dsHelper query result:${data}`); + }); + // 删除指定的数据 + dsHelper.delete(dseUri, predicates, (err, data) => { + console.info(`dsHelper delete result:${data}`); + }); + ``` diff --git a/zh-cn/application-dev/database/share-data-by-silent-access.md b/zh-cn/application-dev/database/share-data-by-silent-access.md new file mode 100644 index 0000000000000000000000000000000000000000..08587ee8e77ea2e56ec44ae4ca0d8d756d4ebf91 --- /dev/null +++ b/zh-cn/application-dev/database/share-data-by-silent-access.md @@ -0,0 +1,46 @@ +# 通过静默数据访问实现数据共享 + + +## 场景介绍 + +据大数据统计,典型跨应用访问数据的用户场景下,一个用户一天平均拉起次数接近83次。 + +为了降低应用拉起次数,提高访问速度,OpenHarmony提供了一种不拉起数据提供方直接访问数据库的方式,即静默数据访问。 + +静默数据仅支持数据库的基本访问,如果有业务处理,建议将业务处理放到数据访问方。 + +如果业务过于复杂,无法放到数据访问方,建议通过DataShareExtensionAbility拉起数据提供方实现功能。 + + +## 运作机制 + +**图1** 静默数据访问视图 + +![silent_dataShare](figures/silent_dataShare.jpg) + +- 和跨应用数据共享方式不同的是,静默数据访问借助数据管理服务通过目录映射方式直接读取数据提供方的配置,按规则进行预处理后,并访问数据库。 + +- 数据访问方如果使用静默数据访问方式,URI需严格按照如下格式: + datashare:///{bundleName}/{moduleName}/{storeName}/{tableName}?Proxy=true + + Proxy=true表示通过静默方式访问数据不拉起数据提供方,如果没有此项则会拉起数据提供方。 + + 数据管理服务会读取对应bundleName作为数据提供方应用,读取配置,进行权限校验并访问对应数据。 + + +## 约束与限制 + +- 目前仅关系型数据库支持静默数据访问方式。 + +- 整个系统最多同时并发16路查询,有多出来的查询请求需要排队处理。 + +- 不支持代理创建数据库,如果需要创建数据库,需要拉起数据提供方。 + + +## 实现说明 + +URI需严格按照如下格式: + +datashare:///{bundleName}/{moduleName}/{storeName}/{tableName}?Proxy=true + +其他开发步骤与实现,具体可参照[通过DataShareExtensionAbility实现数据共享](share-data-by-datashareextensionability.md)。 diff --git a/zh-cn/application-dev/database/share-device-data-across-apps-overview.md b/zh-cn/application-dev/database/share-device-data-across-apps-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..1dc4ae9e99e5712af37f1311caa9c50a1cd2f748 --- /dev/null +++ b/zh-cn/application-dev/database/share-device-data-across-apps-overview.md @@ -0,0 +1,46 @@ +# 同设备跨应用数据共享概述 + + +## 功能简介 + +数据共享(DataShare) 提供了向其他应用共享以及管理其数据的方法,支持同个设备上不同应用之间的数据共享。 + +在许多应用场景中都需要用到数据共享,比如将电话簿、短信、媒体库中的数据共享给其他应用等。当然,不是所有的数据都允许其他应用访问,比如帐号、密码等;有些数据也只允许其他应用查询而不允许其删改,比如短信等。所以对于各种数据共享场景,DataShare这样一个安全、便捷的可以跨应用的数据共享机制是十分必要的。 + +数据提供者无需进行繁琐的封装,可直接使用DataShare向其他应用共享数据;对数据访问方来说,因DataShare的访问方式不会因数据提供的方式而不同,只需要学习和使用一套接口即可,大大减少了学习时间和开发难度。 + +跨应用数据共享有两种方式: + +- **使用DataShareExtensionAbility实现数据共享** + 这种方式通过在HAP中实现一个extension,在extension中可以实现回调,在访问方调用对应接口时,会自动拉起提供方对应的extension,并调用对应回调。 + + 这种方式适用于跨应用数据访问时有业务的操作,不仅是对数据库的增删改查的情况。 + +- **通过静默访问实现数据共享** + 这种方式通过在HAP中配置数据库的访问规则,在访问方调用对应接口时,会自动通过系统服务读取HAP配置规则,按照规则返回数据,不会拉起数据提供方。 + + 这种方式适用于跨应用数据访问仅为数据库的增删改查,没有特殊业务的情况。 + + +## 基本概念 + +在进行同设备跨应用数据共享开发前,先了解以下相关概念。 + +- **数据提供方**:提供数据及实现相关业务的应用程序,也称为生产者或服务端。 + +- **数据访问方**:访问数据提供方所提供的数据或业务的应用程序,也称为消费者或客户端。 + +- **数据集**:用户要插入的数据集合,可以是一条或多条数据。数据集以键值对的形式存在,键为字符串类型,值支持数字、字符串、布尔值、无符号整型数组等多种数据类型。 + +- **结果集**:用户查询之后的结果集合,其提供了灵活的数据访问方式,以便用户获取各项数据。 + +- **谓词**:用户访问数据库中的数据所使用的筛选条件,经常被应用在更新数据、删除数据和查询数据等场景。 + + +## 约束限制 + +- DataShare受到数据提供方所使用数据库的一些限制。例如支持的数据模型、Key的长度、Value的长度、每个应用程序支持同时打开数据库的最大数量等,都会受到使用的数据库的限制。 + +- 因DataShare内部实现依赖于IPC通信,所以数据集、谓词、结果集等的载荷受到IPC通信的约束与限制。 + +- 当前仅支持在Stage模型下,进行同设备跨应用数据共享相关能力的开发。 diff --git a/zh-cn/application-dev/database/sync-app-data-across-devices-overview.md b/zh-cn/application-dev/database/sync-app-data-across-devices-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..b2dd3568b674fe10544872ebcb90d00a55a063f9 --- /dev/null +++ b/zh-cn/application-dev/database/sync-app-data-across-devices-overview.md @@ -0,0 +1,49 @@ +# 同应用跨设备数据同步概述 + + +## 场景介绍 + +跨设备数据同步功能(即分布式功能),指将数据同步到一个组网环境中的其他设备。常用于用户应用程序数据内容在可信认证的不同设备间,进行自由同步、修改和查询。 + +例如:当设备1上的应用A在分布式数据库中增、删、改数据后,设备2上的应用A也可以获取到该数据库变化。可在分布式图库、备忘录、联系人、文件管理器等场景中使用。 + +不同应用间订阅数据库变化通知,请参考[同设备跨应用数据共享](share-device-data-across-apps.md)实现。 + +根据跨设备同步数据生命周期不同,可以分为: + +- 临时数据生命周期较短,通常保存内存中。比如游戏应用产生的过程数据,建议使用分布式数据对象; + +- 持久数据生命周期较长,需要保存到存储的数据库中,根据数据关系和特点,选择关系型或者键值型数据库。比如图库应用的各种相册、封面、图片等属性信息,建议使用关系型数据库;图库应用的具体图片缩略图,建议使用键值型数据库。 + + +## 基本概念 + +在分布式场景中,会涉及多个设备,组网内设备之间看到的数据是否一致称为分布式数据库的一致性。 + + +分布式数据库一致性可以分为强一致性、弱一致性和最终一致性。 + + +- 强一致性:是指某一设备成功增、删、改数据后,组网内设备对该数据的读取操作都将得到更新后的值。对于已改变写的数据的读取,最终都能取得已更新的数据,但不完全保证能立即取得已更新的数据。 + +- 弱一致性:是指某一设备成功增、删、改数据后,组网内设备可能读取到本次更新后的数据,也可能读取不到,不能保证在多长时间后每个设备的数据一定是一致的。 + +- 最终一致性:是指某一设备成功增、删、改数据后,组网内设备可能读取不到本次更新后的数据,但在某个时间窗口之后组网内设备的数据能够达到一致状态。 + + +强一致性对分布式数据的管理要求非常高,在服务器的分布式场景可能会遇到。因为移动终端设备的不常在线、以及无中心的特性,所以同应用跨设备数据同步不支持强一致性,只支持最终一致性。 + + +## 跨设备同步访问控制机制 + +数据跨设备同步时,数据管理基于设备等级和[数据安全标签](access-control-by-device-and-data-level.md#基本概念)进行访问控制。规则为,数据只允许向数据安全标签不高于设备安全等级的设备同步数据,具体访问控制矩阵如下: + +|设备安全级别|可同步的数据安全标签| +|---|---| +|SL1|S1| +|SL2|S1~S2| +|SL3|S1~S3| +|SL4|S1~S4| +|SL5|S1~S4| + +例如,对于类似rk3568、hi3516的开发板设备,设备安全等级为SL1,若创建数据安全标签为S1的数据库,则此数据库数据可以在这些设备间同步;若创建的数据库标签为S2-S4,则不能同步。