sequelize.transaction() 可以将异步函数作为回调吗?

Posted

技术标签:

【中文标题】sequelize.transaction() 可以将异步函数作为回调吗?【英文标题】:Can sequelize.transaction() take async function as callback? 【发布时间】:2019-11-05 17:45:23 【问题描述】:

因此,阅读Instance 上的 Sequelize 文档以及有关 transactions 的文档,sequelize.transaction()autoCallback 函数作为参数。文档说:

回调是用事务对象调用的,应该返回 一个承诺。如果 promise 得到解决,则事务提交;如果 promise 拒绝,事务回滚

但是我计划在事务内部做很多事情,我想避免回调地狱。所以我试着做

try 
    let result = sequelize.transaction(
            isolationLevel: 'SERIALIZABLE'
        , async t => 
            // code to run here with await
            let var1 = await Model.find( transaction: t );
            let var2 = await Model.find( transaction: t );

            if (var1.id === 1)
                return "Whatever result";
            else
                throw new Error("Something wicked");
        
    ));

    // Whatever result
    console.log(result);
catch(e)
    // Something wicked

这似乎工作得很好。但它完全没有记录,我还没有看到有人使用它。可以吗,还是我会遇到随机问题?

【问题讨论】:

不确定您所说的“完全无证”是什么意思。文档说“应该返回一个承诺”,而您使用的是 async function,所以一切都很好? @Bergi 是的,我希望一切都好。我只是要求确认。如果我理解正确,我不能从异步回调函数返回一个承诺(如 return Model.find()),但我必须始终返回一个值本身(如 return await Model.find()),对吗? @michnovka 每个异步函数都会返回一个承诺。如果 Model.find 返回一个 promise,那么 return Model.find()return await Model.find() 之间没有显着差异。 【参考方案1】:

正如 @Bergi 和 @Nicholas Tower 在 cmets 中指出的那样:

由于异步函数总是返回承诺,而回调函数应该返回承诺,这是一个相当直截了当的答案。

是的,可以使用。

【讨论】:

【参考方案2】:

如果您想使用直接 async/await,请参见下文。您也没有将事务(代码中的t)传递给查询,因此他们不会使用它 - 您必须在transaction 选项中显式传递它。如果您在提交事务后进行任何更改,如果有任何错误,则随后将其回滚。您还可以通过与Promise.all() 同时运行查询来改进您的代码。

// define outside the try/catch so you can rollback if needed
let transaction;
let result;
try 
    transaction = await sequelize.transaction( isolationLevel: 'SERIALIZABLE' );

    // run concurrently with Promise.all()
    const [ var1, var2 ] = await Promise.all([
       // don't await here, but you have to pass the transaction
       Model.findByPk( transaction ),
       Model.findOne( transaction ), // ditto
    ]);

    if (var1.id === 1) 
       result = "Whatever result";
     else 
       throw new Error("Something wicked");
    
    // if you need to commit anything...
    // await transaction.commit();
 catch(err) 
    /* if you need to roll back anything...
    if (transaction) 
       await transaction.rollback();
    
    */
    console.log(err);

return result;

【讨论】:

感谢您的回复,但即使您的解决方案确实有效,我的也是。但是不提供事务函数回调,需要手动调用commit()和rollback()。在为函数提供回调的情况下,这将由 sequelize 自动处理。还是谢谢 @michnovka 事务没有被传递给查询,所以它没有被使用。不过,您的答案是正确的。 @michnovka 提交和回滚将自动发生,但我发现这不是生产应用程序的最佳实践,因为最好控制回滚发生的时间点,以防您需要在之后执行任何操作,但那是并非所有用例都如此,因此在示例中已将其注释掉。

以上是关于sequelize.transaction() 可以将异步函数作为回调吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 forEach 问题中对事务进行后续处理

在 forEach 问题中对交易进行序列化。

可拖动+可排序和可滚动的 div

在可放置容器内防止 jQueryUI 可排序触发可放置事件

jQuery:可拖动连接到可排序。可拖动项目与可排序列表具有不同的 DOM

如何制作可用于可查询的可重用条件? [复制]