Sequelize-nodejs-8-Transactions


Transactions事務

Sequelize supports two ways of using transactions:

Sequelize支持兩種使用transactions的方法

  • One which will automatically commit or rollback the transaction based on the result of a promise chain and, (if enabled) pass the transaction to all calls within the callback一是基於promise鏈的結果去自動提交或回滾事務,(如果可以)並在回調中傳遞事務給所有調用
  • And one which leaves committing, rolling back and passing the transaction to the user.另一個則放棄提交、回滾和傳遞事務給用戶

The key difference is that the managed transaction uses a callback that expects a promise to be returned to it while the unmanaged transaction returns a promise.

主要的不同在管理事務使用了promise被返回給它的回調,然而非管理交易也返回promise

 

 

Managed transaction (auto-callback)管理事務

Managed transactions handle committing or rolling back the transaction automagically. You start a managed transaction by passing a callback to sequelize.transaction.

管理事務將自動處理提交或回滾事務。你通過傳遞回調給sequelize.transaction來開始一個管理事務。

Notice how the callback passed to transaction returns a promise chain, and does not explicitly call t.commit() nor t.rollback(). If all promises in the returned chain are resolved successfully the transaction is committed. If one or several of the promises are rejected, the transaction is rolled back.

注意,回調怎么被傳給事務將返回一個promise鏈,並不顯式地調用 t.commit()t.rollback()。如果在返回鏈中的所有的promise都成功解決,事務將被提交。如果一個或一些promise被拒絕,事務將回滾。

return sequelize.transaction(function (t) {

  // chain all your queries here. make sure you return them.
  return User.create({
    firstName: 'Abraham',
    lastName: 'Lincoln'
  }, {transaction: t}).then(function (user) {
    return user.setShooter({
      firstName: 'John',
      lastName: 'Boothe'
    }, {transaction: t});
  });

}).then(function (result) {
  // Transaction has been committed
  // result is whatever the result of the promise chain returned to the transaction callback
}).catch(function (err) {
  // Transaction has been rolled back
  // err is whatever rejected the promise chain returned to the transaction callback
});

 

Throw errors to rollback拋出錯誤給回滾

When using the managed transaction you should never commit or rollback the transaction manually. If all queries are successful, but you still want to rollback the transaction (for example because of a validation failure) you should throw an error to break and reject the chain:

當使用管理事務時,你絕不應該手動提交或回滾事務。如果所有的查詢都成功了,但是你仍然想要回滾事務(比如因為驗證失敗),你應該拋出一個錯誤去停止事務,並拒絕加入鏈中:

return sequelize.transaction(function (t) {
  return User.create({
    firstName: 'Abraham',
    lastName: 'Lincoln'
  }, {transaction: t}).then(function (user) {
    // Woops, the query was successful but we still want to roll back!
    throw new Error();
  });
});

 

Automatically pass transactions to all queries自動傳遞事務給所有查詢

In the examples above, the transaction is still manually passed, by passing { transaction: t } as the second argument. To automatically pass the transaction to all queries you must install the continuation local storage(CLS) module and instantiate a namespace in your own code:

在上面的例子中,事務都是手動傳遞,通過傳遞{ transaction: t }作為第二變量。為了自動傳遞事務給所有查詢,你一定要安裝continuation local storage(CLS) 模塊並在你的代碼中實例化一個命名空間

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

To enable CLS you must tell sequelize which namespace to use by using a static method of the sequelize constructor:

為了使用CLS,你一定要通過sequelize構造函數的靜態方法告訴sequelize使用的是那個命名空間:

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

new Sequelize(....);

Notice, that the useCLS() method is on the constructor, not on an instance of sequelize. This means that all instances will share the same namespace, and that CLS is all-or-nothing - you cannot enable it only for some instances.

注意,useCLS()方法是在構造函數中,而不是在sequelize中的。這意味着所有實例都可以共享這個命名空間,CLS是all-or-nothing的-你不可能只能在一些實例中使用它

CLS works like a thread-local storage for callbacks. What this means in practice is that different callback chains can access local variables by using the CLS namespace. When CLS is enabled sequelize will set the transactionproperty on the namespace when a new transaction is created. Since variables set within a callback chain are private to that chain several concurrent transactions can exist at the same time:

CLS像回調的本地線程存儲一樣工作。這意味着在實際中,當事務創建時不同的回調鏈能夠通過CLS命名空間調用本地變量。因此回調鏈中的變量集對於該鏈都是私有的,多個並發事務可以同時存在;

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

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

In most case you won't need to access namespace.get('transaction') directly, since all queries will automatically look for a transaction on the namespace:

在更多情況下,我們不需要直接訪問namespace.get('transaction'),因此所有查詢將自動在命名空間中查找事務

sequelize.transaction(function (t1) {
  // With CLS enabled, the user will be created inside the transaction
  return User.create({ name: 'Alice' });
});

After you've used Sequelize.useCLS() all promises returned from sequelize will be patched to maintain CLS context. CLS is a complicated subject - more details in the docs for cls-bluebird, the patch used to make bluebird promises work with CLS.

在你使用 Sequelize.useCLS()之后,所有從sequelize中返回的promises將被修補去保持CLS上下文。CLS是復雜的主題-更多細節在文檔cls-bluebird

Note: _CLS only supports async/await, at the moment, when using cls-hooked package. Although, cls-hookedrelies on experimental API async_hooks_

 

 

 

Concurrent/Partial transactions並發/局部事務

You can have concurrent transactions within a sequence of queries or have some of them excluded from any transactions. Use the {transaction: } option to control which transaction a query belong to:

在一系列查詢中你可以有並發事務或一部分被事務排除

Warning: SQLite does not support more than one transaction at the same time.

SQLite不支持一次超過一個事務

Without CLS enabled

sequelize.transaction(function (t1) {
  return sequelize.transaction(function (t2) {
    // With CLS enable, queries here will by default use t2
    // Pass in the `transaction` option to define/alter the transaction they belong to.
    return Promise.all([
        User.create({ name: 'Bob' }, { transaction: null }),
        User.create({ name: 'Mallory' }, { transaction: t1 }),
        User.create({ name: 'John' }) // this would default to t2
    ]);
  });
});

 

 

 

Isolation levels

The possible isolations levels to use when starting a transaction:

在開始事務是可能的隔離級別:

Sequelize.Transaction.ISOLATION_LEVELS.READ_UNCOMMITTED // "READ UNCOMMITTED"
Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED // "READ COMMITTED"
Sequelize.Transaction.ISOLATION_LEVELS.REPEATABLE_READ  // "REPEATABLE READ"
Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE // "SERIALIZABLE"

By default, sequelize uses the isolation level of the database. If you want to use a different isolation level, pass in the desired level as the first argument:

默認sequelize使用數據庫的隔離級別。如果你想要使用不同的隔離級別,傳遞你心儀的級別作為第一變量

return sequelize.transaction({
  isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE
  }, function (t) {

  // your transactions

  });

Note: The SET ISOLATION LEVEL queries are not logged in case of MSSQL as the specified isolationLevel is passed directly to tedious

 

 

 

Unmanaged transaction (then-callback)非管理事務

Unmanaged transactions force you to manually rollback or commit the transaction. If you don't do that, the transaction will hang until it times out. To start an unmanaged transaction, call sequelize.transaction()without a callback (you can still pass an options object) and call then on the returned promise. Notice that commit() and rollback() returns a promise.

非管理事務強迫你手動地回滾或提交事務。如果你不想這么做,事務將被掛起直至超時。為了開始非管理事務,調用沒有回調的sequelize.transaction()(你還是可以傳遞選項options對象的)並在返回的promise中調用then。注意 commit()rollback()都返回promise

return sequelize.transaction().then(function (t) {
  return User.create({
    firstName: 'Bart',
    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();
  });
});

 

 

 

Options

The transaction method can be called with an options object as the first argument, that allows the configuration of the transaction.

事務方法可以帶着options對象作為第一參數來被調用,options允許事務的配置

return sequelize.transaction({ /* options */ });

The following options (with their default values) are available:

下面的options(帶着默認值)是可用的:

{
  autocommit: true,
  isolationLevel: 'REPEATABLE_READ',
  deferrable: 'NOT DEFERRABLE' // implicit default of postgres
}

The isolationLevel can either be set globally when initializing the Sequelize instance or locally for every transaction:

當初始化Sequelize示例時,對每個事務isolationLevel要么被設置為全局的,要么是局部的

// globally
new Sequelize('db', 'user', 'pw', {
  isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE
});

// locally
sequelize.transaction({
  isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE
});

The deferrable option triggers an additional query after the transaction start that optionally set the constraint checks to be deferred or immediate. Please note that this is only supported in PostgreSQL.

在🍜開始之后,deferrable選項觸發額外的查詢,將選擇性地將限制查看設置為deferred或immediate。

請注明這個只在PostgreSQL中使用

sequelize.transaction({
  // to defer all constraints:
  deferrable: Sequelize.Deferrable.SET_DEFERRED,

  // to defer a specific constraint:
  deferrable: Sequelize.Deferrable.SET_DEFERRED(['some_constraint']),

  // to not defer constraints:
  deferrable: Sequelize.Deferrable.SET_IMMEDIATE
})

 

 

 

Usage with other sequelize methods

The transaction option goes with most other options, which are usually the first argument of a method. For methods that take values, like .create, .update(), .updateAttributes() etc. transaction should be passed to the option in the second argument. If unsure, refer to the API documentation for the method you are using to be sure of the signature.

事務選項有着很多其他的options,通常都是方法的第一參數。比如獲取值的方法像.create, .update(), .updateAttributes()等,事務應該在第二個參數中傳遞option。如果不確定,就參考API文檔。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM