在云开发数据库文档中其实有一些事务处理的指引和demo,不过基本都是await风格的,只能在异步函数里面使用。
有的时候希望用『同步函数+callback』的方式代替await来实现更好的并发执行能力,那就需要用promise的编程风格了,写了个demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| exports.main_handler = (event, context , callback) => { let collectionName = "test",commitState = false, n = 500; db.startTransaction().then(transaction=>{ transaction.collection(collectionName).add([ {_id:Math.floor(Math.random()*n),a:1}, {_id:Math.floor(Math.random()*n),a:2}, ]).then(res=>{ return transaction.collection(collectionName).add({_id:Math.floor(Math.random()*n),b:2}) }).then(res=>{ return transaction.collection(collectionName).add({_id:Math.floor(Math.random()*n),b:2}) }).then(res=>{ commitState=true; return transaction.commit() }).then(res=>{ callback(null,{code:0,msg:"事务提交成功: "+JSON.stringify(res)}) },rej=>{ if(commitState){ transaction.rollback().then(res=>{ callback(null,"提交失败,回滚成功") },rej=>{ callback(null,"提交失败,回滚失败") }) }else{ callback(null,"事务创建失败,尚未提交,无需回滚") } }) },()=>{ console.log("开启事务失败") callback(null,"开启事务失败") }) };
|
代码中刻意使用了500内的随机整数来当id来制造随机的id冲突以随机初发事务的失败。
其实如果能用Promise.all的化代码还能更好看些
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| db.startTransaction().then(transaction=>{ for(var i=0;i<5;i++){ p.push(transaction.collection(collectionName).add({_id:Math.floor(Math.random()*n),a:3})) } Promise.all(p).then(res=>{ transaction.commit().then(res=>{ callback(null,{code:0,msg:"事务提交成功: "+JSON.stringify(res)}) },rej=>{ transaction.rollback().then( res=>{ callback(null,"提交失败,回滚成功") },rej=>{ console.log(rej) callback(null,"提交失败,回滚失败") }) }) },rej=>{ console.log(rej) callback(null,"事务创建失败,尚未提交,无需回滚") }) },()=>{ callback(null,"开启事务失败") })
|
但是云开发数据库的sdk不支持这么玩。Promise.all里的数据库操作一多起来,就有一定的概率触发这样的错误:
TcbError: [ResourceUnavailable.TransactionBusy] Transaction is busy.
暂时只能用上面的一步一步then的方式来执行了,或者用网上流行的Array.reduce的方式来让Promise排队执行。