微信小程序云开发如何实现数据库自动备份实现
前言
数据是无价的,我们通常会把重要的业务数据存放在数据库中,并需要对数据库做定时的自动备份工作,防止数据异常丢失,造成无法挽回的损失。
小程序云开发提供了方便的云数据库供我们直接使用,云开发使用了腾讯云提供的云数据库,拥有完善的数据保障机制,无需担心数据丢失。但是,我们还是不可避免的会担心数据库中数据的安全,比如不小心删除了数据集合,写入了脏数据等。
还好,云开发控制台提供了数据集合的导出,导入功能,我们可以手动备份数据库。不过,总是手动备份数据库也太麻烦了点,所有重复的事情都应该让代码去解决,下面我们就说说怎么搞定云开发数据库自动备份。
通过查阅微信的文档,可以发现云开发提供了数据导出接口databaseMigrateExport
POSThttps://api.weixin.qq.com/tcb/databasemigrateexport?access_token=ACCESS_TOKEN
通过这个接口,结合云函数的定时触发功能,我们就可以做数据库定时自动备份了。梳理一下大致的流程:
- 创建一个定时触发的云函数
- 云函数调用接口,导出数据库备份文件
- 将备份文件上传到云存储中以供使用
1.获取access_token
调用微信的接口需要access_token,所以我们首先要获取access_token。通过文档了解到使用auth.getAccessToken接口可以用小程序的appid和secret获取access_token。
//获取access_token request.get( `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`, (err,res,body)=>{ if(err){ //处理错误 return; } constdata=JSON.parse(body); //data.access_token } );
2.创建数据库导出任务
获取access_token后,就可以使用databaseMigrateExport接口导出数据进行备份。
databaseMigrateExport接口会创建一个数据库导出任务,并返回一个job_id,这个job_id怎么用我们下面再说。显然数据库的数据导出并不是同步的,而是需要一定时间的,数据量越大导出所要花费的时间就越多,个人实测,2W条记录,2M大小,导出大概需要3~5S。
调用databaseMigrateExport接口需要传入环境Id,存储文件路径,导出文件类型(1为JSON,2为CSV),以及一个query查询语句。
因为我们是做数据库备份,所以这里就导出JSON类型的数据,兼容性更好。需要备份的数据可以用query来约束,这里还是很灵活的,既可以是整个集合的数据,也可以是指定的部分数据,这里我们就使用db.collection('data').get()备份data集合的全部数据。同时我们使用当前时间作为文件名,方便以后使用时查找。
request.post( `https://api.weixin.qq.com/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; } constdata=JSON.parse(body); //data.job_id } );
3.查询任务状态,获取文件地址
在创建号数据库导出任务后,我们会得到一个job_id,如果导出集合比较大,就会花费较长时间,这时我们可以使用databaseMigrateQueryInfo接口查询数据库导出的进度。
当导出完成后,会返回一个file_url,即可以下载数据库导出文件的临时链接。
request.post(`https://api.weixin.qq.com/tcb/databasemigratequeryinfo?access_token=${accessToken}`, { body:JSON.stringify({ env, job_id:jobId }) }, (err,res,body)=>{ if(err){ reject(err); } constdata=JSON.parse(body); //data.file_url } );
获取到文件下载链接之后,我们可以将文件下载下来,存入到自己的云存储中,做备份使用。如果不需要长时间的保留备份,就可以不用下载文件,只需要将job_id存储起来,当需要恢复备份的时候,通过job_id查询到新的链接,下载数据恢复即可。
至于job_id存在哪,就看个人想法了,这里就选择存放在数据库里。
awaitdb.collection('db_back_info').add({ data:{ date:newDate(), jobId:job_id } });
4.函数定时触发器
云函数支持定时触发器,可以按照设定的时间自动执行。云开发的定时触发器采用的Cron表达式语法,最大精度可以做的秒级,详细的使用方法可以参考官方文档:定时触发器|微信开放文档
这里我们配置函数每天凌晨2点触发,这样就可以每天都对数据库进行备份。在云函数目录下新建config.json文件,写入如下内容:
{ "triggers":[ { "name":"dbTrigger", "type":"timer", "config":"002****" } ] }
完整代码
最后,贴出可以在云函数中使用的完整代码,只需要创建一个定时触发的云函数,并设置好相关的环境变量即可使用
- appid
- secret
- backupColl:需要备份的集合名称,如‘data'
- backupInfoColl:存储备份信息的集合名称,如‘db_back_info'
注意,云函数的默认超时时间是3秒,创建备份函数时,建议将超时时间设定到最大值20S,留有足够的时间查询任务结果。
/*eslint-disable*/ constrequest=require('request'); constcloud=require('wx-server-sdk'); //环境变量 constenv='xxxx'; cloud.init({ env }); //换取access_token asyncfunctiongetAccessToken(appid,secret){ returnnewPromise((resolve,reject)=>{ request.get( `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`, (err,res,body)=>{ if(err){ reject(err); return; } resolve(JSON.parse(body)); } ); }); } //创建导出任务 asyncfunctioncreateExportJob(accessToken,collection){ constdate=newDate().toISOString(); returnnewPromise((resolve,reject)=>{ request.post( `https://api.weixin.qq.com/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)); } ); }); } //查询导出任务状态 asyncfunctionwaitJobFinished(accessToken,jobId){ returnnewPromise((resolve,reject)=>{ //轮训任务状态 consttimer=setInterval(()=>{ request.post( `https://api.weixin.qq.com/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}=process.env; constdb=cloud.database(); try{ //获取access_token const{errmsg,access_token}=awaitgetAccessToken(appid,secret); if(errmsg&&errcode!==0){ thrownewError(`获取access_token失败:${errmsg}`||'获取access_token为空'); } //导出数据库 const{errmsg:jobErrMsg,errcode:jobErrCode,job_id}=awaitcreateExportJob(access_token,backupColl); //打印到日志中 console.log(job_id); if(jobErrCode!==0){ thrownewError(`创建数据库备份任务失败:${jobErrMsg}`); } //将任务数据存入数据库 constres=awaitdb.collection('db_back_info').add({ data:{ date:newDate(), jobId:job_id } }); //等待任务完成 constfileUrl=awaitwaitJobFinished(access_token,job_id); console.log('导出成功',fileUrl); //存储到数据库 awaitdb .collection(backupInfoColl) .doc(res._id) .update({ data:{ fileUrl } }); }catch(e){ thrownewError(`导出数据库异常:${e.message}`); } };
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。