⼩程序云开发如何实现数据库⾃动备份实现
前⾔
数据是⽆价的,我们通常会把重要的业务数据存放在数据库中,并需要对数据库做定时的⾃动备份⼯作,防⽌数据异常丢失,造成⽆法挽回的损失。
⼩程序云开发提供了⽅便的云数据库供我们直接使⽤,云开发使⽤了腾讯云提供的云数据库,拥有完善的数据保障机制,⽆需担⼼数据丢失。但是,我们还是不可避免的会担⼼数据库中数据的安全,⽐如不⼩⼼删除了数据集合,写⼊了脏数据等。
还好,云开发控制台提供了数据集合的导出,导⼊功能,我们可以⼿动备份数据库。不过,总是⼿动备份数据库也太⿇烦了点,所有重复的事情都应该让代码去解决,下⾯我们就说说怎么搞定云开发数据库⾃动备份。
通过查阅的⽂档,可以发现云开发提供了数据导出接⼝
POST api.weixin.qq/tcb/databasemigrateexport?access_token=ACCESS_TOKEN
通过这个接⼝,结合云函数的定时触发功能,我们就可以做数据库定时⾃动备份了。梳理⼀下⼤致的流程:
创建⼀个定时触发的云函数
云函数调⽤接⼝,导出数据库备份⽂件
将备份⽂件上传到云存储中以供使⽤
1. 获取 access_token
调⽤的接⼝需要 access_token,所以我们⾸先要获取 access_token。通过⽂档了解到使⽤ AccessToken 接⼝可以⽤⼩程序的 appid 和 secret 获取 access_token。
// 获取 access_token
<(
`api.weixin.qq/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`,
(err, res, body) => {
if (err) {
// 处理错误
return;
}
const data = JSON.parse(body);
// data.access_token
}
);
2. 创建数据库导出任务
获取 access_token 后,就可以使⽤ databaseMigrateExport 接⼝导出数据进⾏备份。
databaseMigrateExport 接⼝会创建⼀个数据库导出任务,并返回⼀个 job_id,这个 job_id 怎么⽤我们下⾯再说。显然数据库的数据导出并不是同步的,⽽是需要⼀定时间的,数据量越⼤导出所要花费的时间就越多,个⼈实测,2W 条记录,2M ⼤⼩,导出⼤概需要 3~5 S。
调⽤ databaseMigrateExport 接⼝需要传⼊环境 Id,存储⽂件路径,导出⽂件类型(1 为 JSON,2 为 CSV),以及⼀个query 查询语句。
因为我们是做数据库备份,所以这⾥就导出 JSON 类型的数据,兼容性更好。需要备份的数据可以⽤ query 来约束,这⾥还是很灵活的,既可以是整个集合的数据,也可以是指定的部分数据,这⾥我们就使⽤ db.collection('data').get() 备份 data 集合的全部数据。同时我们使⽤当前时间作为⽂件名,⽅便以后使⽤时查。
request.post(
`api.weixin.qq/tcb/databasemigrateexport?access_token=${accessToken}`,
{
body: JSON.stringify({
env,
file_path: `${date}.json`,
file_type: '1',
query: 'db.collection("data").get()'
})
},
(err, res, body) => {
if (err) {
// 处理错误
return;
}
const data = JSON.parse(body);
// data.job_id
}
)
;
3. 查询任务状态,获取⽂件地址
在创建号数据库导出任务后,我们会得到⼀个 job_id,如果导出集合⽐较⼤,就会花费较长时间,这时我们可以使⽤databaseMigrateQueryInfo 接⼝查询数据库导出的进度。
当导出完成后,会返回⼀个 file_url,即可以下载数据库导出⽂件的临时链接。
request.post( `api.weixin.qq/tcb/databasemigratequeryinfo?access_token=${accessToken}`,
{
body: JSON.stringify({
env,
job_id: jobId
})
},
(err, res, body) => {
if (err) {
reject(err);
}
const data = JSON.parse(body);
// data.file_url
}
数据库怎么备份数据);
获取到⽂件下载链接之后,我们可以将⽂件下载下来,存⼊到⾃⼰的云存储中,做备份使⽤。如果不需要长时间的保留备份,就可以不⽤下载⽂件,只需要将 job_id 存储起来,当需要恢复备份的时候,通过 job_id 查询到新的链接,下载数据恢复即可。
⾄于 job_id 存在哪,就看个⼈想法了,这⾥就选择存放在数据库⾥。
llection('db_back_info').add({
data: {
date: new Date(),
jobId: job_id
}
});
4. 函数定时触发器
云函数⽀持定时触发器,可以按照设定的时间⾃动执⾏。云开发的定时触发器采⽤的 Cron 表达式语法,最⼤精度可以做的秒级,详细的使⽤⽅法可以参考官⽅⽂档:定时触发器 | 开放⽂档
这⾥我们配置函数每天凌晨 2 点触发,这样就可以每天都对数据库进⾏备份。在云函数⽬录下新建 config.json⽂件,写⼊如下内容:
{
"triggers": [
{
"name": "dbTrigger",
"type": "timer",
"config": "0 0 2 * * * *"
}
]
}
完整代码
最后,贴出可以在云函数中使⽤的完整代码,只需要创建⼀个定时触发的云函数,并设置好相关的环境变量即可使⽤
appid
secret
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({
env
});
// 换取 access_token
async function getAccessToken(appid, secret) {
return new Promise((resolve, reject) => {
<(
`api.weixin.qq/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`, (err, res, body) => {
if (err) {
reject(err);
return;
}
resolve(JSON.parse(body));
}
);
});
}
// 创建导出任务
async function createExportJob(accessToken, collection) {
const date = new Date().toISOString();
return new Promise((resolve, reject) => {
request.post(
`api.weixin.qq/tcb/databasemigrateexport?access_token=${accessToken}`,
{
body: JSON.stringify({
env,
file_path: `${date}.json`,
file_type: '1',
query: `db.collection("${collection}").get()`
})
},
(err, res, body) => {
if (err) {
reject(err);
}
resolve(JSON.parse(body));
}
);
});
}
// 查询导出任务状态
async function waitJobFinished(accessToken, jobId) {
return new Promise((resolve, reject) => {
// 轮训任务状态
const timer = setInterval(() => {
request.post(
`api.weixin.qq/tcb/databasemigratequeryinfo?access_token=${accessToken}`,
{
body: JSON.stringify({
env,
job_id: jobId
})
},
(err, res, body) => {
if (err) {
reject(err);
}
const { status, file_url } = JSON.parse(body);
console.log('查询');
if (status === 'success') {
clearInterval(timer);
resolve(file_url);
}
}
);
}, 500);
});
}
exports.main = async (event, context) => {
// 从云函数环境变量中读取 appid 和 secret 以及数据集合
const { appid, secret, backupColl, backupInfoColl } = v;
const db = cloud.database();
try {
// 获取 access_token
const { errmsg, access_token } = await getAccessToken(appid, secret);
if (errmsg && errcode !== 0) {
throw new Error(`获取 access_token 失败:${errmsg}` || '获取 access_token 为空');
}
/
/ 导出数据库
const { errmsg: jobErrMsg, errcode: jobErrCode, job_id } = await createExportJob(access_token, backupColl); // 打印到⽇志中
console.log(job_id);
if (jobErrCode !== 0) {
throw new Error(`创建数据库备份任务失败:${jobErrMsg}`);
}
// 将任务数据存⼊数据库
const res = llection('db_back_info').add({
data: {
date: new Date(),
jobId: job_id
}
});
// 等待任务完成
const fileUrl = await waitJobFinished(access_token, job_id);
console.log('导出成功', fileUrl);
// 存储到数据库
await db
.collection(backupInfoColl)
.doc(res._id)
.update({
data: {
fileUrl
}
});
} catch (e) {
throw new Error(`导出数据库异常:${e.message}`);
}
};
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论