云开发数据库的事务处理

2022-01-07 16:32:54 浏览数 (2)

在云开发数据库文档中其实有一些事务处理的指引和demo,不过基本都是await风格的,只能在异步函数里面使用,有的时候希望用『同步函数 callback』的方式代替await来实现更好的并发执行能力,那就需要用promise的编程风格了,写了个demo:

代码语言:javascript复制
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的化代码还能更好看些

代码语言:javascript复制
    /* 以下代码会触发云开发数据库sdk的bug */
    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排队执行。

0 人点赞