sequelize-----transaction事物的处理

今天在这里,想记录一下自己的getting,对于nodejs关联mysql的问题;

我们都知道,在执行增删改查的时候,查是不需要事物的而我们的增删改是需要事物的,那么我们怎么给我们的增删改加事物呢?

下面我们就来看一下:

其实在这里加事物的话有我认为有这么几种:

1 手动提交事物和回滚的非托管方式;

2  自动提交和回滚的托管方式;

3  就是使用CLS命名空间的方式去实现并行事物;

在这里我们先来看最简单的托管方式:

首先,

Sequelize 支持两种使用事务的方法:

  • 一个将根据 promise 链的结果自动提交或回滚事务,(如果启用)用回调将该事务传递给所有调用
  • 而另一个 leave committing,回滚并将事务传递给用户。

主要区别在于托管事务使用一个回调,对非托管事务而言期望 promise 返回一个 promise 的结果。

托管事物:

托管事务自动处理提交或回滚事务。你可以通过将回调传递给 sequelize.transaction 来启动托管事务。

注意回传传递给 transaction 的回调是否是一个 promise 链,并且没有明确地调用t.commit()t.rollback()。 如果返回链中的所有 promise 都已成功解决,则事务被提交。 如果一个或几个 promise 被拒绝,事务将回滚。

比r说:

return sequelize.transaction(function (t) {

  // 在这里链接您的所有查询。 确保你返回他们。
  return User.create({
    firstName: 'Abraham',
    lastName: 'Lincoln'
  }, {transaction: t}).then(function (user) {
    return user.setShooter({
      firstName: 'John',
      lastName: 'Boothe'
    }, {transaction: t});
  });

}).then(function (result) {
  // 事务已被提交
  // result 是 promise 链返回到事务回调的结果
}).catch(function (err) {
  // 事务已被回滚
  // err 是拒绝 promise 链返回到事务回调的错误
});

这里是create的方式,但我们用到的更新会相对来说多一些,这里我们就以更新为例子:

废话不多说 直接看代码,我们以转账威力,一个是更新订单的状态,一个是去转账,一个事物更新交易记录,

当然这些model大家自己去建立la

//这里我们会加上where条件去具体更新确定的一条记录
//事物的开启用的就是sequelize.transaction
return sequelize.transaction(function (t) {
           //这里我们首先更新订单实体,并且加入条件和事物,注意里的条件和事物是并列存在的
           //再者就是这里.then的方式就是相当于一个promise链,
           //当你去使用并行事物的时候可以去考虑promise.all去实现这个后面会有介绍
		return OrderModel.update({
				order_status: 'complete',
				accepted_at: Date.now(),
				completed_at: Date.now(),
			},
			{
				where: {id: order.id},
				transaction: t
			}
		).then((res)=>{
              //第二个我们去更新账户,即进行转账操作,同样加入事物
			console.log("order updated",res);
			return  AccountModel.update({
					bonus: selleraccount.bonus-order.price,
					balance: selleraccount.balance+order.price,
					updated_at: Date.now(),
				},
				{
					where: {user_id : order.seller_id},
					transaction : t
				}
			);

		}).then(function (res) {
              //最后去更新交易记录
			console.log("account updated",res);
			// throw new Error();
                        //这里是用来测试的,大家可以认出一个异常去看看,有没有回滚
			return TransactionModel.update({
					status : CONSTANT.TRANSACTION_STATUS.SUCCESS,
					// updated_at : Date.now()
				},
				{
					where : { sn : order.sn},
					transaction : t
				}
			);

		});

	});

 2 .自动将事务传递给所有查询

 在上面的例子中,事务仍然是手动传递的,通过传递 {transaction:t} 作为第二个参数。 要自动将事务传递给所有查询,您必须安装 continuation local storage (CLS) 模块,并在您自己的代码中实例化一个命名空间:

const cls = require('continuation-local-storage'),
    namespace = cls.createNamespace('my-very-own-namespace'

 要启用CLS,您必须通过使用sequelize构造函数的静态方法来告诉Sequelize要使用的命名空间:

const Sequelize = require('sequelize');
Sequelize.useCLS(namespace);

new Sequelize(....);

请注意, useCLS() 方法在 构造函数 上,而不是在 sequelize 的实例上。 这意味着所有实例将共享相同的命名空间,并且 CLS 是全部或全无方式 - 你不能仅在某些实例中启用它。

CLS 的工作方式就像一个用于回调的本地线程存储。 这在实践中意味着不同的回调链可以通过使用 CLS 命名空间来访问局部变量。 当启用 CLS 时,创建新事务时,Sequelize 将在命名空间上设置 transaction 属性。 由于回调链中设置的变量对该链是私有的,因此可以同时存在多个并发事务:

sequelize.transaction(function (t1) {
  namespace.get('transaction') === t1; // true
});

sequelize.transaction(function (t2) {
  namespace.get('transaction') === t2; // true
});

 在大多数情况下,你不需要直接访问 namespace.get('transaction'),因为所有查询都将自动在命名空间中查找事务:

 sequelize.transaction(function (t1) {
  // 启用 CLS 后,将在事务中创建用户
  return User.create({ name: 'Alice' });
});

在使用 Sequelize.useCLS() 后,从 sequelize 返回的所有 promise 将被修补以维护 CLS 上下文。 CLS 是一个复杂的课题 - cls-bluebird的文档中有更多细节,用于使 bluebird promise 的补丁与CLS一起工作。

 3  并行/部分事务

你可以在一系列查询中执行并发事务,或者将某些事务从任何事务中排除。 使用 {transaction: } 选项来控制查询所属的事务,------promise.all

不启用CLS

sequelize.transaction(function (t1) {
  return sequelize.transaction(function (t2) {
    // 启用CLS,这里的查询将默认使用 t2    
    // 通过 `transaction` 选项来定义/更改它们所属的事务。
        return Promise.all([
        User.create({ name: 'Bob' }, { transaction: null }),
        User.create({ name: 'Mallory' }, { transaction: t1 }),
        User.create({ name: 'John' }) // 这将默认为 t2
    ]);
  });
});

4 非托管事务(then-callback)

非托管事务强制您手动回滚或提交交易。 如果不这样做,事务将挂起,直到超时。 要启动非托管事务,请调用 sequelize.transaction() 而不用 callback(你仍然可以传递一个选项对象),并在返回的 promise 上调用 then。 请注意,commit()rollback() 返回一个 promise。

return sequelize.transaction().then(function (t) {
  return User.create({
    firstName: 'Homer',
    lastName: 'Simpson'
  }, {transaction: t}).then(function (user) {
    return user.addSibling({
      firstName: 'Lisa',
      lastName: 'Simpson'
    }, {transaction: t});
  }).then(function () {
    return t.commit();
  }).catch(function (err) {
    return t.rollback();
  });
});

 transaction 选项与其他大多数选项一起使用,通常是方法的第一个参数。
对于取值的方法,如 .create, .update(), .updateAttributes() 等。应该传递给第二个参数的选项。

猜你喜欢

转载自blog.csdn.net/qq_42112846/article/details/83217130