node.js 使用 oracledb 执行事务控制

背景

承接前面一篇介绍 node.js 封装数据库操作的文章,本文继续封装 node.js 中通过oracledb进行事务操作的实现过程。oracledb 相比 mysql 好一点的是它的所有操作同时支持回调和 Promise 两种处理方式,所以编写同一个事务中执行多个 SQL 的逻辑,其代码相比 mysql 更简洁。

async 和 await 的控制流程

首先,需要了解下 async 和 await 结合使用时,如果 await 返回的是一个 reject 结果,那么我们的同步代码该怎么处理呢?从执行过程来看,只要进行 catch 操作,那么 try 分支中所有接受到 reject 的 Promise 对象的操作都会进入到 catch 分支。

简单写个例子验证下:

async function test(){
    try {
       await hello1();
       await hello2();
       console.log("OK finish");
    }catch (err) {
       console.log(err);
    }
}

function hello1(){
   return new Promise(async(resolve, reject) => {
	   console.log("hello1 bad");
	   reject({
                    status: 0,
                    message: '操作失败'
       });
   });
}

function hello2(){
   return new Promise(async(resolve, reject) => {
	   	console.log("hello2 ok");
	   resolve({
           status: 1,
           message: '操作成功'
      });
   });
}

test();

执行结果为:
在这里插入图片描述

oracledb 事务操作封装

oracledb 如果在同一个 connection 中调用 execute 操作,那么这些操作都是通过一个事务处理的,所以实现思路是将所有待执行的 SQL 语句放在一个 connection 调用方法中完成,结合 await ,在 try 分支中最后显式调用 commit ,异常分支调用 rollback 回滚。

const oracledb = require('oracledb');

/**
 * 创建执行SQL
 * @param sql
 * @param param
 * @returns {{sql: *, param: *}}
 */
function buildSqlParamEntity(sql, param) {
    return {
        sql: sql,
        param: param
    }
}

/**
 * 在同一个事务中执行多条SQL语句,都是异步方式
 * @param sqlparamsEntities
 * @param callback
 * @returns {Promise.<void>}
 */
async function oracleExecTrans(sqlparamsEntities,callback){
    logger.info("Oracle execute transaction");

    if(sqlparamsEntities==null || sqlparamsEntities.length==0){
        logger.info("Statement is null,do nothing.")
        return;
    }

   let connection;
    try {
        // Get a connection from the default pool
        connection = await oracledb.getConnection();

        //遍历语句进行执行:在同一个connection中执行的SQl,都是默认为一个事务的。
        for (var i = 0; i < sqlparamsEntities.length; i++) {
            var sql = sqlparamsEntities[i].sql;
            var params = sqlparamsEntities[i].param;
            let results = await connection.execute(sql, params);
            logger.info(sql+"results is:"+results);
        }

        //提交事务
        await connection.commit();

        //释放连接
        connection.release();

        //执行回调:传入成功消息
        callback('操作成功',null);
    } catch (err) {
        console.error(err);

        //异常:则进行事务回滚
        if(connection!=undefined && connection!=null){
            await connection.rollback();
            await connection.release();
        }

        //执行回调:传入异常信息
        callback(null,err);
    }
}

进入 catch 分支的可能是由 getConnection() 引起的,也可能是 execute 或者 commit 导致的,所以在异常分支执行回滚操作需要判断连接对象是否存在。以同步的逻辑编写事务处理操作,总的来说代码还是比较简洁的。

至于回调方式实现事务的过程,实在是理不清楚,层层回调下来整个人都凌乱了,还是不浪费脑细胞了吧。

对比 mysql 事务操作实现

网络上搜到的比较完整的 mysql 的事务插入逻辑为:
http://www.cnblogs.com/bk-your/p/7884729.html
由于 mysql 只能通过回调方式调用,所以它在事务处理中使用了 async 模块完成后续的提交或者回滚逻辑:

async.series(funcAry, function (err, result) {
                console.log("transaction error: " + err);
                if (err) {
                    connection.rollback(function (err) {
                        console.log("transaction error: " + err);
                        connection.release();
                        return callback(err, null);
                    });
                } else {
                    connection.commit(function (err, info) {
                        console.log("transaction info: " + JSON.stringify(info));
                        if (err) {
                            console.log("执行事务失败," + err);
                            connection.rollback(function (err) {
                                console.log("transaction error: " + err);
                                connection.release();
                                return callback(err, null);
                            });
                        } else {
                            connection.release();
                            return callback(null, info);
                        }
                    })
                }
            })

启示录

oracledb 的资料也真是少,就连它在 github上 的 api 文档中都没有关于事务的例子,所以只能自己动手编写了。上述代码没有测试环境,所以未经测试,但是已经目测过了,姑且先做参考吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值