1# 通过键值型数据库实现数据持久化 (ArkTS) 2<!--Kit: ArkData--> 3<!--Subsystem: DistributedDataManager--> 4<!--Owner: @ding_dong_dong--> 5<!--Designer: @dboy190; @houpengtao1--> 6<!--Tester: @logic42--> 7<!--Adviser: @ge-yafang--> 8 9 10## 场景介绍 11 12键值型数据库存储键值对形式的数据,当需要存储的数据没有复杂的关系模型,比如存储商品名称及对应价格、员工工号及今日是否已出勤等,由于数据复杂度低,更容易兼容不同数据库版本和设备类型,因此推荐使用键值型数据库持久化此类数据。 13 14 15## 约束限制 16 17- 设备协同数据库,针对每条记录,Key的长度≤896 Byte,Value的长度<4 MB。 18 19- 单版本数据库,针对每条记录,Key的长度≤1 KB,Value的长度<4 MB。 20 21- 每个应用程序最多支持同时打开16个键值型分布式数据库。 22 23- 键值型数据库事件回调方法中不允许进行阻塞操作,例如修改UI组件。 24 25 26## 接口说明 27 28以下是键值型数据库持久化功能的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见[分布式键值数据库](../reference/apis-arkdata/js-apis-distributedKVStore.md)。 29 30| 接口名称 | 描述 | 31| -------- | -------- | 32| createKVManager(config: KVManagerConfig): KVManager | 创建一个KVManager对象实例,用于管理数据库对象。 | 33| getKVStore<T>(storeId: string, options: Options, callback: AsyncCallback<T>): void | 指定options和storeId,创建并得到指定类型的KVStore数据库。 | 34| put(key: string, value: Uint8Array \| string \| number \| boolean, callback: AsyncCallback<void>): void | 添加指定类型的键值对到数据库。 | 35| get(key: string, callback: AsyncCallback\<boolean \| string \| number \| Uint8Array>): void | 获取指定键的值。 | 36| delete(key: string, callback: AsyncCallback<void>): void | 从数据库中删除指定键值的数据。 | 37| closeKVStore(appId: string, storeId: string, callback: AsyncCallback<void>): void | 通过storeId的值关闭指定的分布式键值数据库。 | 38| deleteKVStore(appId: string, storeId: string, callback: AsyncCallback<void>): void | 通过storeId的值删除指定的分布式键值数据库。 | 39 40 41## 开发步骤 42 431. 若要使用键值型数据库,首先要使用createKVManager()方法获取一个KVManager实例,用于管理数据库对象。示例代码如下所示: 44 45 Stage模型示例: 46 47 48 ```js 49 // 导入模块 50 import { distributedKVStore } from '@kit.ArkData'; 51 52 // Stage模型 53 import { window } from '@kit.ArkUI'; 54 import { UIAbility } from '@kit.AbilityKit'; 55 import { BusinessError } from '@kit.BasicServicesKit'; 56 57 let kvManager: distributedKVStore.KVManager | undefined = undefined; 58 let appId: string = 'com.example.datamanagertest'; 59 let storeId: string = 'storeId'; 60 export default class EntryAbility extends UIAbility { 61 onCreate() { 62 let context = this.context; 63 const kvManagerConfig: distributedKVStore.KVManagerConfig = { 64 context: context, 65 bundleName: appId 66 }; 67 try { 68 // 创建KVManager实例 69 kvManager = distributedKVStore.createKVManager(kvManagerConfig); 70 console.info('Succeeded in creating KVManager.'); 71 // 继续创建获取数据库 72 if (kvManager !== undefined) { 73 //进行后续操作 74 //... 75 } 76 } catch (e) { 77 let error = e as BusinessError; 78 console.error(`Failed to create KVManager. Code:${error.code},message:${error.message}`); 79 } 80 } 81 } 82 ``` 83 84 FA模型示例: 85 86 87 ```js 88 // 导入模块 89 import { distributedKVStore } from '@kit.ArkData'; 90 91 // FA模型 92 import { featureAbility } from '@kit.AbilityKit'; 93 import { BusinessError } from '@kit.BasicServicesKit'; 94 95 let kvManager: distributedKVStore.KVManager | undefined = undefined; 96 let appId: string = 'com.example.datamanagertest'; 97 let storeId: string = 'storeId'; 98 let context = featureAbility.getContext(); // 获取context 99 const kvManagerConfig: distributedKVStore.KVManagerConfig = { 100 context: context, 101 bundleName: appId 102 }; 103 try { 104 kvManager = distributedKVStore.createKVManager(kvManagerConfig); 105 console.info('Succeeded in creating KVManager.'); 106 // 继续创建获取数据库 107 } catch (e) { 108 let error = e as BusinessError; 109 console.error(`Failed to create KVManager. Code:${error.code},message:${error.message}`); 110 } 111 if (kvManager !== undefined) { 112 //进行后续操作 113 //... 114 } 115 116 ``` 117 1182. 使用getKVStore()方法创建并获取键值数据库。示例代码如下所示: 119 120 ```js 121 let kvStore: distributedKVStore.SingleKVStore | undefined = undefined; 122 try { 123 let child1 = new distributedKVStore.FieldNode('id'); 124 child1.type = distributedKVStore.ValueType.INTEGER; 125 child1.nullable = false; 126 child1.default = '1'; 127 let child2 = new distributedKVStore.FieldNode('name'); 128 child2.type = distributedKVStore.ValueType.STRING; 129 child2.nullable = false; 130 child2.default = 'zhangsan'; 131 132 let schema = new distributedKVStore.Schema(); 133 schema.root.appendChild(child1); 134 schema.root.appendChild(child2); 135 schema.indexes = ['$.id', '$.name']; 136 // 0表示COMPATIBLE模式,1表示STRICT模式。 137 schema.mode = 1; 138 // 支持在检查Value时,跳过skip指定的字节数,且取值范围为[0,4M-2]。 139 schema.skip = 0; 140 141 const options: distributedKVStore.Options = { 142 createIfMissing: true, 143 encrypt: false, 144 backup: false, 145 autoSync: false, 146 // kvStoreType不填时,默认创建多设备协同数据库 147 kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, 148 // 多设备协同数据库:kvStoreType: distributedKVStore.KVStoreType.DEVICE_COLLABORATION, 149 schema: schema, 150 // schema未定义可以不填,定义方法请参考上方schema示例。 151 securityLevel: distributedKVStore.SecurityLevel.S3 152 }; 153 kvManager.getKVStore<distributedKVStore.SingleKVStore>(storeId, options, (err, store: distributedKVStore.SingleKVStore) => { 154 if (err) { 155 console.error(`Failed to get KVStore: Code:${err.code},message:${err.message}`); 156 return; 157 } 158 console.info('Succeeded in getting KVStore.'); 159 kvStore = store; 160 // 请确保获取到键值数据库实例后,再进行相关数据操作 161 if (kvStore !== undefined) { 162 //进行后续操作 163 //... 164 } 165 }); 166 } catch (e) { 167 let error = e as BusinessError; 168 console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`); 169 } 170 ``` 171 1723. 使用on()方法订阅分布式数据变化,如需关闭订阅分布式数据变化,调用[off('dataChange')](../reference/apis-arkdata/js-apis-distributedKVStore.md#offdatachange)关闭。示例代码如下所示: 173 174 ```ts 175 try { 176 kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, (data) => { 177 console.info(`dataChange callback call data: ${data}`); 178 }); 179 } catch (e) { 180 let error = e as BusinessError; 181 console.error(`An unexpected error occurred. code:${error.code},message:${error.message}`); 182 } 183 ``` 184 1854. 调用put()方法向键值数据库中插入数据。示例代码如下所示: 186 187 ```js 188 const KEY_TEST_STRING_ELEMENT = 'key_test_string'; 189 // 如果未定义Schema则Value可以传其他符合要求的值。 190 const VALUE_TEST_STRING_ELEMENT = '{"id":0, "name":"lisi"}'; 191 try { 192 kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => { 193 if (err !== undefined) { 194 console.error(`Failed to put data. Code:${err.code},message:${err.message}`); 195 return; 196 } 197 console.info('Succeeded in putting data.'); 198 }); 199 } catch (e) { 200 let error = e as BusinessError; 201 console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`); 202 } 203 ``` 204 205 > **说明:** 206 > 207 > 当Key值存在时,put()方法会修改其值,否则新增一条数据。 208 2095. 调用get()方法获取指定键的值。示例代码如下所示: 210 211 ```js 212 try { 213 kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => { 214 if (err !== undefined) { 215 console.error(`Failed to put data. Code:${err.code},message:${err.message}`); 216 return; 217 } 218 console.info('Succeeded in putting data.'); 219 kvStore = kvStore as distributedKVStore.SingleKVStore; 220 kvStore.get(KEY_TEST_STRING_ELEMENT, (err, data) => { 221 if (err != undefined) { 222 console.error(`Failed to get data. Code:${err.code},message:${err.message}`); 223 return; 224 } 225 console.info(`Succeeded in getting data. Data:${data}`); 226 }); 227 }); 228 } catch (e) { 229 let error = e as BusinessError; 230 console.error(`Failed to get data. Code:${error.code},message:${error.message}`); 231 } 232 ``` 233 2346. 调用delete()方法删除指定键值的数据。示例代码如下所示: 235 236 ```js 237 try { 238 kvStore.put(KEY_TEST_STRING_ELEMENT, VALUE_TEST_STRING_ELEMENT, (err) => { 239 if (err !== undefined) { 240 console.error(`Failed to put data. Code:${err.code},message:${err.message}`); 241 return; 242 } 243 console.info('Succeeded in putting data.'); 244 kvStore = kvStore as distributedKVStore.SingleKVStore; 245 kvStore.delete(KEY_TEST_STRING_ELEMENT, (err) => { 246 if (err !== undefined) { 247 console.error(`Failed to delete data. Code:${err.code},message:${err.message}`); 248 return; 249 } 250 console.info('Succeeded in deleting data.'); 251 }); 252 }); 253 } catch (e) { 254 let error = e as BusinessError; 255 console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`); 256 } 257 ``` 258 2597. 调用closeKVStore()方法通过storeId的值关闭指定的分布式键值数据库。示例代码如下所示: 260 261 ```js 262 try { 263 // appId为应用的bundleName 264 kvManager = kvManager as distributedKVStore.KVManager; 265 kvStore = undefined; 266 kvManager.closeKVStore(appId, storeId, (err: BusinessError)=> { 267 if (err) { 268 console.error(`Failed to close KVStore.code is ${err.code},message is ${err.message}`); 269 return; 270 } 271 console.info('Succeeded in closing KVStore'); 272 }); 273 } catch (e) { 274 let error = e as BusinessError; 275 console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`); 276 } 277 ``` 278 2798. 调用deleteKVStore()方法通过storeId的值删除指定的分布式键值数据库。示例代码如下所示: 280 281 ```js 282 try { 283 // appId为应用的bundleName 284 kvManager = kvManager as distributedKVStore.KVManager; 285 kvStore = undefined; 286 kvManager.deleteKVStore(appId, storeId, (err: BusinessError)=> { 287 if (err) { 288 console.error(`Failed to delete KVStore.code is ${err.code},message is ${err.message}`); 289 return; 290 } 291 console.info('Succeeded in deleting KVStore'); 292 }); 293 } catch (e) { 294 let error = e as BusinessError; 295 console.error(`An unexpected error occurred. Code:${error.code},message:${error.message}`); 296 } 297 ``` 298 299<!--RP1--><!--RP1End-->