在Knex.js中的transaction.commit之后插入执行

时间:2019-07-12 19:31:31

标签: node.js knex.js asynchronous-javascript

我想在完成事务之前在事务中并行执行插入。我使用Promise.all()和bluebird promises来取消所有的promise。问题在于,在实际执行插入操作之前,承诺似乎已经结束。我正在使用Knex.js。我有2个诺言,一个是在用户表中插入用户名和用户的电子邮件,另一个是对用户密码进行加密,然后在登录表中插入电子邮件和已加密的密码。

我已经找到了执行承诺和插入的顺序。他们以这种方式执行。 (插入用户名和电子邮件的承诺得到解决)->(Knex调试器说运行了用于用户名和电子邮件的插入命令)->(承诺比插入电子邮件和密码得到解决)->(transaction.commit)->(Knex调试器说,已经运行了用于电子邮件和密码的插入命令,但是事务已经结束,并且引发了错误)。这里的问题显然是电子邮件和密码承诺在插入电子邮件和密码之前被执行了。

Future<String> futureFunction() async {
    RekognitionHandler rekognition = new RekognitionHandler(accessKey, secretKey, region);
        if(sourceImagefile !=null && targetImagefile !=null) {
          var labelsArray = await rekognition.compareFaces(
              sourceImagefile, targetImagefile);
          print(labelsArray);

          return labelsArray.toString();
        } else {
            return "enter image";
        }
}

我希望登录表和用户表都将被更新,但是由于事务提交是在​​将登录更新添加到事务中之前发生的,因此仅更新了用户表。这是我在Knex中使用debugging = true运行程序时收到的错误消息:

const addUser = (username, email, password) => {
    return db.transaction(trx => {
        let addLoginEntry = Promise.resolve(bcrypt.hash(password, 10)
            .then(secret => {
                trx("login").insert({
                    email: email,
                    secret: secret
                }).then(console.log("PASSWORD INSERTED"));
            })
        );

        let addUserEntry = Promise.resolve(
            trx("users").insert({
                username: username,
                email: email
            })
            .then(console.log("USER INFO INSERTED"))
        )

        Promise.all([
            addLoginEntry,
            addUserEntry
        ])
        .then(args => {
            console.log("All promises done");
            trx.commit(args);
        })
        .catch(error => {
            [addLoginEntry, addUserEntry].forEach(promise =>promise.cancel());
            console.log(error);
            trx.rollback();
        });
    });
}

1 个答案:

答案 0 :(得分:1)

您在那里缺少一个return语句,并且您的调试打印代码也有错误。我添加了评论以解释在那里发生的事情:

return db.transaction(trx => {
    let addLoginEntry = Promise.resolve(bcrypt.hash(password, 10)
        .then(secret => {
            // ---- MISSING RETURN HERE and PASSWORD INSERTED
            // actually runs before query is even executed.
            // should be .then(() => console.log("PASSWORD INSERTED"))
            // to make that debug print line to be evaluated as part of
            // promise chain
            trx("login").insert({
                email: email,
                secret: secret
            }).then(console.log("PASSWORD INSERTED"));
        })
    );

    // also here USER INFO INSERTED is logged before
    // query is even executed during evaluating query builder
    // method parameters
    let addUserEntry = Promise.resolve(
        trx("users").insert({
            username: username,
            email: email
        })
        .then(console.log("USER INFO INSERTED"))
    )

    // at this point of code USER INFO INSERTED is already printed
    // user add query is ran concurrently with bcrypt call and then 
    // this is resolved and execution continues ....
    Promise.all([
        addLoginEntry,
        addUserEntry
    ])
    .then(args => {
        // .... continues here and concurrently also login insert query is 
        // created and PASSWORD INSERTED log is printed out
        console.log("All promises done");

        // for some reason .commit() gets executed before login insert query is
        // actually triggered. It could have also worked correctly with
        // some luck.
        trx.commit(args);
    })
    .catch(error => {
        [addLoginEntry, addUserEntry].forEach(promise =>promise.cancel());
        console.log(error);
        trx.rollback();
    });
});

所以是的,基本上只缺少一条return语句。