本文正在參加星光計劃3.0–夏日挑戰賽
(#夏日挑戰賽#【FFH】分布式資料服務簡單實作(OpenHarmony JS UI版))
Demo效果展示
先來看看我們要實作的demo的效果。點選同步資料的按鈕後,A裝置廣播一段字元串到資料庫中,然後B裝置讀取到變化後将接收到的字元串渲染出來。

分布式資料服務概述
HarmonyOS提供了我們在不同裝置之間可以擷取相同的資料,稱之為分布式資料庫,隻要是信任的裝置就都可以擷取到儲存在分布式資料庫裡面的資料。是以一般都是在不同裝置之間要擷取相同資料的場景下使用該資料庫。
KV資料模型
“KV資料模型”是“Key-Value資料模型”的簡稱,“Key-Value”即“鍵-值”。它是一種NoSQL(非關系型資料存儲系統)資料庫,其資料以鍵值對的形式進行組織、索引和存儲。
因為KV資料模型用于不涉及過多資料關系和業務關系的資料存儲,是以比傳統的SQL資料存儲擁有更多的讀寫性能。
分布式資料庫同步
底層通信元件完成裝置發現和認證,會通知上層應用程式(包括分布式資料服務)裝置上線。收到裝置上線的消息後分布式資料服務可以在兩個裝置之間建立加密的資料傳輸通道,利用該通道在兩個裝置之間進行資料同步。
分布式資料服務提供了兩種同步方式:手動同步和自動同步。
- 手動同步:由應用程式調用sync接口來觸發,需要指定同步的裝置清單和同步模式。同步模式分為PULL_ONLY(将遠端資料拉到本端)、PUSH_ONLY(将本端資料推送到遠端)和PUSH_PULL(将本端資料推送到遠端同時也将遠端資料拉取到本端)。内部接口支援按條件過濾同步,将符合條件的資料同步到遠端。
- 自動同步:包括全量同步和按條件訂閱同步。全量同步由分布式資料庫自動将本端資料推送到遠端,同時也将遠端資料拉取到本端來完成資料同步,同步時機包括裝置上線、應用程式更新資料等,應用不需要主動調用sync接口;内部接口支援按條件訂閱同步,将遠端符合訂閱條件的資料自動同步到本端。
單版本分布式資料庫
單版本是指資料在本地儲存是以單個KV條目為機關的方式儲存,對每個Key最多隻儲存一個條目項,當資料在本地被使用者修改時,不管它是否已經被同步出去,均直接在這個條目上進行修改。同步也以此為基礎,按照它在本地被寫入或更改的順序将目前最新一次修改逐條同步至遠端裝置。
簡單來說單版本分布式資料庫是通過鍵值對(Key、Value)的形式儲存資料,隻能有一個key不能重複,當本地key資料被修改的時候會被直接修改,然後将最新的資料再同步出去
裝置協同分布式資料庫
裝置協同分布式資料庫建立在單版本分布式資料庫之上,對應用程式存入的KV資料中的Key前面拼接了本裝置的DeviceID辨別符,這樣能保證每個裝置産生的資料嚴格隔離,底層按照裝置的次元管理這些資料,裝置協同分布式資料庫支援以裝置的次元查詢分布式資料,但是不支援修改遠端裝置同步過來的資料。
簡單來說就是在單版本分布式資料庫的key前面拼接上本裝置的裝置id,保證每個裝置的資料庫能夠區分,知道是哪個裝置添加進去的資料;但是不能修改遠端裝置同步過來的資料,就是在A裝置添加的鍵值對資料推送到B裝置,B裝置隻能讀取該資料,不能對該資料進行修改。
下面我們簡單寫一個分布式資料庫的demo,進入代碼實戰環節。
代碼封裝
一個項目中,用到分布式資料庫的地方可能不止一處。為了提高代碼的複用性以及友善後續維護,就需要對這部分代碼進行封裝。
是以我們這裡先建立一個子產品檔案,然後再該檔案内建立一個js子產品(這裡我建立的子產品命名為kv.js),在這裡面将分布式資料服務的代碼進行封裝。後續要使用到相關的功能我們隻需要調用這個檔案即可,可以有效避免重複性的工作同時提高代碼的可讀性。
導入子產品
建立一個單獨的js檔案,進行資料庫子產品封裝,友善後續調用。
import distributedData from '@ohos.data.distributedData';
建立分布式資料庫
建立分布式資料庫分為三步:
- 建立KvManagerConfig對象
- 其中bundleName要和自己建立的工程保持一緻
- 建立分布式資料庫管理器
- 這裡option中的kvStoreType參數要注意一下,0是裝置協同分布式資料庫,1是單版本資料庫,差別上面已經提到,如果沒有特殊業務,一般選擇單版本資料庫。
- 其中option中的securityLevel等級越高,限制越多。
- 擷取分布式資料庫
下面是具體實作代碼:
createKvStore(callback) {
if (typeof (this.kvStore) === 'undefined') {
//建立KvManagerConfig對象
var config = {
bundleName: 'com.example.myapplication',
userInfo: {
userId: '0',
userType: 0
}
};
let self = this;
distributedData.createKVManager(config).then((manager) => {
//建立分布式資料庫管理器
self.kvManager = manager;
var options = {
createIfMissing: true,
encrypt: false,
backup: false,
autoSync: true,
kvStoreType: 1,
//等級越高,限制越多
securityLevel: 1,
};
self.kvManager.getKVStore(STORE_ID, options).then((store) => {
self.kvStore = store;
callback();
});
});
} else {
callback();
}
}
增删改查
增删改查接口就比較簡單,先來簡單看一下api接口功能及參數:
-
插入和更新資料: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>
然後接下來我們來編寫增删改查的代碼
插入和更新資料
sendMessage(key,value) {
let self = this;
this.createKvStore(() => {
self.put(key,value);
});
}
put(key,value) {
console.info('data is changing...' );
this.kvStore.put(key,value).then((data) => {
console.info('dataChange:' + JSON.stringify(data));
this.kvStore.get(key).then((data) => {
console.info('dataChange:' + JSON.stringify(data));
});
}).catch((err) => {
});
}
删除資料
delete(key) {
this.kvStore.delete(key).then((data) => {
}).catch((err) => {
});
}
查詢資料
get(key) {
this.kvStore.get(key).then((data) => {
}).catch((err) => {
});
}
訂閱資料變化
-
訂閱資料變化:on(event: 'dataChange', type: SubscribeType, observer: Callback<ChangeNotification>): void
on(event: 'syncComplete', syncCallback: Callback<Array<[string, number]>>): void
setOnMessageReceivedListener(callback) {
let self = this;
this.createKvStore(() => {
self.kvStore.on('dataChange', 1, (data) => {
console.info('dataChange:' + JSON.stringify(data));
for (var i = 0; i < data.updateEntries.length; i++) {
var str = data.updateEntries[0].value.value;
callback(data.updateEntries[0].key,str, 1);
return;
}
});
});
}
到此我們就已經完成了代碼的封裝。
代碼調用
封裝好了之後,我們接下來隻需要進行簡單的調用即可,首先需要建立一個page,這裡我們就拿index這個頁面來進行一個簡單的demo編寫。
步驟隻有三步:
- 擷取相關權限
- 封裝子產品調用
- 界面渲染
擷取permisssion權限
在config.json中添加permisssion權限
"reqPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
}
]
添加位置如下圖:
在初始頁面申請使用者權限
編寫一個申請權限函數,然後再初始化頁面時調用。
import featureAbility from '@ohos.ability.featureAbility';
export default {
onInit() {
this.grantPermission();
},
grantPermission() {
console.info('Calc[IndexPage] grantPermission')
let context = featureAbility.getContext()
context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (res) {
console.log("chw---get permission result:"+res)
})
},
}
封裝子產品調用
導入已封裝的分布數資料庫子產品
import KvStoreModel from '../../model/kv.js';
建立執行個體
data: {
kvStoreModel: new KvStoreModel(),
},
訂閱分布式資料庫消息通知
onInit() {
console.log("chw---init start")
this.grantPermission();
// type表示操作0:插入資料、1:修改資料:2:删除資料
this.kvStoreModel.setOnMessageReceivedListener((k, v, type1) => {
console.log("chw---is listening")
//傳過來是的字元串,要解序列化為 JSON對象
this.testReceiveStr =v;
this.isReceiveInfo= true;
this.changeType=type1;
console.log("chw---receive data:"+v);
});
console.log("chw---init end")
},
廣播同步資料
send(){
var that=this;
//這裡注意如果發送資料類型是對象或者數組需要将對象或者數組序列化成 JSON字元串
this.kvStoreModel.sendMessage(that.key,"消息123");
console.log("chw---is sending")
},
js完整代碼
import featureAbility from '@ohos.ability.featureAbility';
import KvStoreModel from '../../model/kv.js';
export default {
data: {
kvStoreModel: new KvStoreModel(),
isReceiveInfo:false,
changeType:1,
key:"openharmony",
testReceiveStr:"nothing"
},
onInit() {
console.log("chw---init start")
this.grantPermission();
// type表示操作0:插入資料、1:修改資料:2:删除資料
this.kvStoreModel.setOnMessageReceivedListener((k, v, type1) => {
console.log("chw---is listening")
//傳過來是的字元串,要解序列化為 JSON對象
this.testReceiveStr =v;
this.isReceiveInfo= true;
this.changeType=type1;
console.log("chw---receive data:"+v);
});
console.log("chw---init end")
},
grantPermission() {
let context = featureAbility.getContext()
context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (res) {
// console.log("chw---get permission result:"+res)
})
},
send(){
var that=this;
//這裡注意如果發送資料類型是對象或者數組需要将對象或者數組序列化成 JSON字元串
this.kvStoreModel.sendMessage(that.key,"消息123");
console.log("chw---is sending")
},
}
界面渲染
為了友善看到資料同步的情況,當然,也可以打開控制台檢視列印的資訊。
這裡我們選擇直接渲染出資料同步情況,在hml檔案中添加以下代碼:
<div class="container">
<text class="title" if="{{isReceiveInfo}}">
接收資訊:{{ testReceiveStr }}
</text>
<button type="capsule" onclick="send" style="width: 300px;height: 100px;">
同步資料
</button>
</div>
這樣我們就完整做完一個分布式資料庫的小demo了。
附件連結:https://ost.51cto.com/resource/2075