Node.js 7如何使用异步/等待的sequelize事务?

时间:2017-03-18 04:12:31

标签: transactions sequelize.js

Node.js 7及更高版本已经支持async / await语法。我应该如何使用asquel / await和sequelize Transactions?

7 个答案:

答案 0 :(得分:90)

let transaction;    

try {
  // get transaction
  transaction = await sequelize.transaction();

  // step 1
  await Model.destroy({where: {id}, transaction});

  // step 2
  await Model.create({}, {transaction});

  // commit
  await transaction.commit();

} catch (err) {
  // Rollback transaction if any errors were encountered
  if (err) await transaction.rollback();
}

答案 1 :(得分:23)

接受的答案是“非托管交易”,要求您明确调用rollbacktry { // Result is whatever you returned inside the transaction let result = await sequelize.transaction( async (t) => { // step 1 await Model.destroy({where: {id: id}, transaction: t}); // step 2 return await Model.create({}, {transaction: t}); }); // In this case, an instance of Model console.log(result); } catch (err) { // Rollback transaction if any errors were encountered console.log(err); } 。对于任何想要“托管交易”的人来说,这就是它的样子:

try {
    // Result is whatever you returned inside the transaction
    let result = await sequelize.transaction( async (t) => {
        // step 1
        await Model.destroy({where: {id:id}, transaction: t});

        // Cause rollback
        if( false ){
            throw new Error('Rollback initiated');
        }

        // step 2
        return await Model.create({}, {transaction: t});
    });

    // In this case, an instance of Model
    console.log(result);
} catch (err) {
    // Rollback transaction if any errors were encountered
    console.log(err);
}

要回滚,只需在事务函数中抛出一个错误:

$(document).ready(function($) {

 
   $( "#accordion").on('click','.accordion-heading', function (e) {
            $return = true;
            if($(this).next('div').is(':visible')== false) $return = false;
            $( "#accordion .panel2").slideUp();
            $("#accordion  .accordion-heading").removeClass('active');
            $(this).next('div').stop(true,false).slideDown();
            $(this).addClass('active');
            return $return;
        });




});

如果任何在事务块中抛出错误的代码,则会自动触发回滚。

答案 2 :(得分:5)

user7403683给出的答案描述了非托管事务的异步/等待方式(http://docs.sequelizejs.com/manual/tutorial/transactions.html#unmanaged-transaction-then-callback-

async / await样式中的托管事务可能如下所示:

await sequelize.transaction( async t=>{
  const user = User.create( { name: "Alex", pwd: "2dwe3dcd" }, { transaction: t} )
  const group = Group.findOne( { name: "Admins", transaction: t} )
  // etc.
})

如果发生错误,则会自动回滚事务。

答案 3 :(得分:4)

上面的代码在销毁调用中有错误。

 await Model.destroy({where: {id}, transaction});

交易是期权对象的一部分。

答案 4 :(得分:0)

对于上述user7403683解决方案的测试范围,请考虑使用 raiserror('msg or var',0,0) with nowait; sequelize-mock

sinon

成功交易:

import SequelizeMock from 'sequelize-mock';
import sinon from 'sinon';

sandbox.stub(models, 'sequelize').returns(new SequelizeMock());

或交易失败:


sandbox.stub(model.sequelize, 'transaction')
          .resolves({commit() {}});

and stub everything in the transaction block

commit() {} provides stubbing of transaction.commit(), 
otherwise you'll get a "method does not exist" error in your tests

测试sandbox.stub(models.sequelize, 'transaction').resolves({rollback() {}}); to cover transaction.rollback() 逻辑。

答案 5 :(得分:0)

async () => {
  let t;

  try {
    t = await sequelize.transaction({ autocommit: true});

    let _user = await User.create({}, {t});

    let _userInfo = await UserInfo.create({}, {t});

    t.afterCommit((t) => {
      _user.setUserInfo(_userInfo);
      // other logic
    });
  } catch (err) {
    throw err;
  }
}

答案 6 :(得分:0)

如果在项目中启用了CLS,则Sequelize可以使用它保留事务对象并将其传递给<template> <div class="subscription"> <div class="email_field"> <input class="email_subscription" type="email" v-model="postEmail" name="email_subscription" placeholder="Email address here" /> </div> <div class="submit_email"> <input type="submit" class="button_submit" @click="submitEmail()" value="Submit" /> </div> </div> </template> <script> export default { data() { return { postEmail: null, language: "en", }; }, methods: { submitEmail() { axios .post( "https://my_api.com/registrations?access_token=my_api_key", { language: this.language, user_email: this.postEmail, auth: { username: "username", password: "password" } } ) .then(response => { // console.log(response); }) .catch(function(error) {}); } } }; </script> 周期内的所有查询。

设置:

continuation-passing

用法:

import { Sequelize } from "sequelize";
import { createNamespace } from "cls-hooked"; // npm i cls-hooked

const cls = createNamespace("transaction-namespace"); // any string
Sequelize.useCLS(cls);

const sequelize = new Sequelize(...);

它如何工作?

从Sequelize源代码中:const removeUser = async (id) => { await sequelize.transaction(async () => { // no need `async (tx)` await removeClasses(id); await User.destroy({ where: { id } }); // will auto receive `tx` }); } const removeClasses = async (userId) => { await UserClass.destroy({ where: { userId } }); // also receive the same transaction object as this function was called inside `sequelize.transaction()` await somethingElse(); // all queries inside this function also receive `tx` }

Check and save transaction to CLS

github.com/sequelize

Retrieve transaction from CSL and set to options

if (useCLS && this.sequelize.constructor._cls) {
    this.sequelize.constructor._cls.set('transaction', this);
}

了解详情:

  1. Sequelize: automatically pass transactions to all queries
  2. CLS hooked
  3. Async Hooks