數據是無價的。我們通常會將重要的業務數據存儲在數據庫中,我們需要對數據庫進行定期的自動備份,以防止非正常的數據丟失和不可挽回的損失。
小程序雲開發提供了壹個方便的雲數據庫,供我們直接使用。雲開發使用騰訊雲提供的雲數據庫,有完善的數據保障機制,不用擔心數據丟失。但是我們難免會擔心數據庫中數據的安全性,比如不小心刪除數據集,寫入臟數據。
好在雲開發控制臺提供了導出和導入數據集的功能,我們可以手動備份數據庫。但是,總是手動備份數據庫太麻煩了。所有重復的事情都應該由代碼來解決。先說壹下如何獲得雲開發數據庫的自動備份。
查閱微信的文檔可以發現,雲開發提供了數據導出接口databaseMigrateExport。
POST/TCB/databasemigmigrateexport?訪問令牌=訪問令牌
通過這個接口,結合雲功能的定時觸發功能,我們可以定期對數據庫進行自動備份。梳理壹下大致流程:
創建壹個定時觸發的雲函數。
雲函數調用接口導出數據庫備份文件。
上傳備份文件到雲存儲使用。
1.獲取訪問令牌
調用微信的接口需要Access_token,所以我們需要先獲取access_token。通過文檔我們知道,使用auth.getAccessToken接口,我們可以用applet的appid和secret獲得access_token。
//獲取access_token
請求.獲取(
`/cgi-bin/token?授權類型=客戶證書。appid = $ { appid } & ampsecret=${secret} `,
(err,res,body)= & gt;{
如果(錯誤){
//處理錯誤
返回;
}
const data = JSON . parse(body);
//data . access _令牌
}
);
2.創建數據庫導出任務
獲取access_token後,可以使用databaseMigrateExport接口導出數據進行備份。
DatabaseMigrateExport接口將創建壹個數據庫導出任務並返回壹個job_id。如何使用這個job_id將在下面討論。顯然,數據庫的數據導出不是同步的,而是需要壹定的時間。數據量越大,導出所需的時間就越長。個人測量,2W記錄,2M的大小,大約需要3~5 S才能導出。
調用databaseMigrateExport接口需要傳入環境Id、存儲文件路徑、導出文件類型(1是JSON,2是CSV)和壹個query查詢語句。
因為我們做的是數據庫備份,所以這裏導出JSON數據,兼容性更強。要備份的數據可以通過查詢來約束,這裏還是很靈活的。它可以是整個集合的數據,也可以是數據的指定部分。這裏我們使用db.collection('data ')。get()來備份數據集合的所有數據。同時我們用當前時間作為文件名,方便以後使用。
request.post(
`/TCB/databasemigmigrateexport?access_token=${accessToken} `,
{
body: JSON.stringify({
env,
file_path: `${date}.json `,
file_type: '1 ',
查詢:' db.collection("data ")。get()'
})
},
(err,res,body)= & gt;{
如果(錯誤){
//處理錯誤
返回;
}
const data = JSON . parse(body);
// data .作業標識
}
);
3.查詢任務狀態並獲取文件地址。
創建數據庫導出任務後,我們將獲得壹個job_id。如果出口收的多,就要花很長時間。此時,我們可以使用databaseMigrateQueryInfo接口來查詢數據庫導出的進度。
導出完成後,將返回壹個file_url,它是下載數據庫導出文件的臨時鏈接。
request . post(`/TCB/databasmigratequeryinfo?access_token=${accessToken} `,
{
body: JSON.stringify({
env,
job_id: jobId
})
},
(err,res,body)= & gt;{
如果(錯誤){
拒絕(err);
}
const data = JSON . parse(body);
// data.file_url
}
);
獲得文件下載鏈接後,我們就可以下載文件,存儲在自己的雲存儲中進行備份。如果不需要長時間保存備份,就不需要下載文件。您只需要存儲job_id。需要恢復備份時,可以通過job_id查詢新鏈接,下載數據進行恢復。
至於job_id存在哪裏,這取決於我個人的想法,所以我選擇存儲在這裏的數據庫中。
await db . collection(' db _ back _ info ')。添加({
數據:{
日期:新日期(),
作業標識:作業標識
}
});
4.功能定時觸發器
雲功能支持定時觸發,可以根據設定的時間自動執行。雲開發的定時觸發采用Cron表達式語法,最大可精確到秒。詳細用法請參考官方文檔:定時觸發|微信打開文檔。
這裏我們將函數配置為每天淩晨2點觸發,這樣每天都可以備份數據庫。在雲函數目錄下新建壹個config.json文件,寫入以下內容:
{
"觸發器":[
{
" name": "dbTrigger ",
"類型":"計時器",
" config": "0 0 2 * * * * "
}
]
}
完全碼
最後貼上可以在雲函數中使用的完整代碼,只需要創建壹個固定時間觸發的雲函數並設置相關環境變量就可以使用了。
appid
秘密
BackupColl:要備份的集合的名稱,例如“data”。
BackupInfoColl:用於存儲備份信息的集合的名稱,如“db _ back _ info”
註意,雲函數的默認超時是3秒。創建備份功能時,建議將超時設置為最大值20S,留出足夠的時間來查詢任務結果。
/* eslint-disable */
const request = require(' request ');
const cloud = require(' wx-server-SDK ');
//環境變量
const env = ' xxxx
cloud.init({
包封/包圍(動詞envelop的簡寫)
});
//換取access_token
異步函數getaccessstoken(appid,secret) {
返回新承諾((解決,拒絕)= & gt{
請求.獲取(
`/cgi-bin/token?授權類型=客戶證書。appid = $ { appid } & ampsecret=${secret} `,
(err,res,body)= & gt;{
如果(錯誤){
拒絕(err);
返回;
}
resolve(JSON . parse(body));
}
);
});
}
//創建導出任務
異步函數createExportJob(accessToken,collection) {
const date =新日期()。toiso string();
返回新承諾((解決,拒絕)= & gt{
request.post(
`/TCB/databasemigmigrateexport?access_token=${accessToken} `,
{
body: JSON.stringify({
env,
file_path: `${date}.json `,
file_type: '1 ',
查詢:` db.collection("${collection} ")。get()`
})
},
(err,res,body)= & gt;{
如果(錯誤){
拒絕(err);
}
resolve(JSON . parse(body));
}
);
});
}
//查詢導出任務狀態
異步函數waitJobFinished(accessToken,jobId) {
返回新承諾((解決,拒絕)= & gt{
//輪訓任務狀態
const timer = setInterval(()= & gt;{
request.post(
`/TCB/databasmigratequeryinfo?access_token=${accessToken} `,
{
body: JSON.stringify({
env,
job_id: jobId
})
},
(err,res,body)= & gt;{
如果(錯誤){
拒絕(err);
}
const { status,file _ URL } = JSON . parse(body);
console . log(' query ');
if (status === 'success') {
clearInterval(定時器);
resolve(file _ URL);
}
}
);
}, 500);
});
}
exports.main = async(事件,上下文)= & gt{
//從雲函數環境變量中讀取appid和secret以及數據集。
const { appid,secret,backupColl,backupInfoColl } = process.env
const db = cloud . database();
嘗試{
//獲取access_token
const { errmsg,access _ token } = await getAccessToken(appid,secret);
if(errmsg & amp;& amp錯誤代碼!== 0) {
拋出新錯誤(“無法獲取access_token:$ { errmsg }”| |“獲取access _ token為空”);
}
//導出數據庫
const { errmsg: jobErrMsg,errcode: jobErrCode,job _ id } = await createExportJob(access _ token,backup coll);
//打印到日誌
console . log(job _ id);
if (jobErrCode!== 0) {
拋出新錯誤(`無法創建數據庫備份任務:$ { jobErrMsg } `);
}
//將任務數據保存在數據庫中。
const RES = await db . collection(' db _ back _ info ')。添加({
數據:{
日期:新日期(),
作業標識:作業標識
}
});
//等待任務完成
const file URL = await waitJobFinished(access _ token,job _ id);
Console.log('導出成功',fileUrl);
//存儲在數據庫中
等待數據庫
。集合(backupInfoColl)
。文檔(資源標識)
。更新({
數據:{
文件Url
}
});
} catch (e) {
拋出新錯誤(`導出數據庫異常:$ { e . message } `);
}
};