Sequelize 中文文檔 v4 - Transactions - 事務

Transactions - 事務

此係列文章的應用示例已發佈於 GitHub: sequelize-docs-Zh-CN. 能夠 Fork 幫助改進或 Star 關注更新. 歡迎 Star.node

Sequelize 支持兩種使用事務的方法:git

  • 一個將根據 promise 鏈的結果自動提交或回滾事務,(若是啓用)用回調將該事務傳遞給全部調用
  • 而另外一個 leave committing,回滾並將事務傳遞給用戶。

主要區別在於託管事務使用一個回調,對非託管事務而言指望 promise 返回一個 promise 的結果。github

託管事務(auto-callback)

託管事務自動處理提交或回滾事務。你能夠經過將回調傳遞給 sequelize.transaction 來啓動託管事務。數據庫

注意回傳傳遞給 transaction 的回調是不是一個 promise 鏈,而且沒有明確地調用t.commit()t.rollback()。 若是返回鏈中的全部 promise 都已成功解決,則事務被提交。 若是一個或幾個 promise 被拒絕,事務將回滾。npm

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 鏈返回到事務回調的錯誤
});

拋出錯誤到回滾

使用託管事務時,你應該 永不 手動提交或回滾事務。 若是全部查詢都成功,但您仍然但願回滾事務(例如由於驗證失敗),則應該拋出一個錯誤來斷開和拒絕連接:promise

return sequelize.transaction(function (t) {
  return User.create({
    firstName: 'Abraham',
    lastName: 'Lincoln'
  }, {transaction: t}).then(function (user) {
    // 查詢成功,但咱們仍然想回滾!
    throw new Error();
  });
});

自動將事務傳遞給全部查詢

在上面的例子中,事務仍然是手動傳遞的,經過傳遞 {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 是所有或全無方式 - 你不能僅在某些實例中啓用它。post

CLS 的工做方式就像一個用於回調的本地線程存儲。 這在實踐中意味着不一樣的回調鏈能夠經過使用 CLS 命名空間來訪問局部變量。 當啓用 CLS 時,建立新事務時,Sequelize 將在命名空間上設置 transaction 屬性。 因爲回調鏈中設置的變量對該鏈是私有的,所以能夠同時存在多個併發事務:ui

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一塊兒工做。

並行/部分事務

你能夠在一系列查詢中執行併發事務,或者將某些事務從任何事務中排除。 使用 {transaction: } 選項來控制查詢所屬的事務:

不啓用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
    ]);
  });
});

隔離等級

啓動事務時可能使用的隔離等級:

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"

默認狀況下,sequelize 使用數據庫的隔離級別。 若是要使用不一樣的隔離級別,請傳入所需級別做爲第一個參數:

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

  //  你的事務

  });

注意: 在MSSQL的狀況下,SET ISOLATION LEVEL 查詢不被記錄, 指定的 isolationLevel 直接傳遞到tedious

非託管事務(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();
  });
});

參數

可使用options對象做爲第一個參數來調用transaction方法,這容許配置事務。

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

如下選項(使用默認值)可用:

{
  autocommit: true,
  isolationLevel: 'REPEATABLE_READ',
  deferrable: 'NOT DEFERRABLE' // postgres 的默認設置
}

在爲 Sequelize 實例或每一個局部事務初始化時,isolationLevel能夠全局設置:

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

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

deferrable 選項在事務開始後觸發一個額外的查詢,可選地將約束檢查設置爲延遲或當即。 請注意,這僅在PostgreSQL中受支持。

sequelize.transaction({
  // 推遲全部約束:
  deferrable: Sequelize.Deferrable.SET_DEFERRED,

  // 推遲具體約束:
  deferrable: Sequelize.Deferrable.SET_DEFERRED(['some_constraint']),

  // 不推遲約束:
  deferrable: Sequelize.Deferrable.SET_IMMEDIATE
})

使用其餘 Sequelize 方法

transaction 選項與其餘大多數選項一塊兒使用,一般是方法的第一個參數。
對於取值的方法,如 .create, .update(), .updateAttributes() 等。應該傳遞給第二個參數的選項。
若是不肯定,請參閱API文檔中的用於肯定簽名的方法。

若是這篇文章對您有幫助, 感謝 下方點贊 或 Star GitHub: sequelize-docs-Zh-CN 支持, 謝謝.

相關文章
相關標籤/搜索