Sequelize官方中文文檔 7. Transactions - 事務(wù)

Sequelize官方GitHub:https://github.com/sequelize/sequelize
Sequelize官方中文文檔:https://github.com/demopark/sequelize-docs-Zh-CN
Sequelize官方英文文檔:http://docs.sequelizejs.com/

Transactions - 事務(wù)

Sequelize 支持兩種使用事務(wù)的方法:

  • 一個將根據(jù) promise 鏈的結(jié)果自動提交或回滾事務(wù),(如果啟用)用回調(diào)將該事務(wù)傳遞給所有調(diào)用
  • 而另一個 leave committing,回滾并將事務(wù)傳遞給用戶。

主要區(qū)別在于托管事務(wù)使用一個回調(diào),對非托管事務(wù)而言期望 promise 返回一個 promise 的結(jié)果。

托管事務(wù)(auto-callback)

托管事務(wù)自動處理提交或回滾事務(wù)。你可以通過將回調(diào)傳遞給 sequelize.transaction 來啟動托管事務(wù)。

注意回傳傳遞給 transaction 的回調(diào)是否是一個 promise 鏈,并且沒有明確地調(diào)用t.commit()t.rollback()。 如果返回鏈中的所有 promise 都已成功解決,則事務(wù)被提交。 如果一個或幾個 promise 被拒絕,事務(wù)將回滾。

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) {
  // 事務(wù)已被提交
  // result 是 promise 鏈返回到事務(wù)回調(diào)的結(jié)果
}).catch(function (err) {
  // 事務(wù)已被回滾
  // err 是拒絕 promise 鏈返回到事務(wù)回調(diào)的錯誤
});

拋出錯誤到回滾

使用托管事務(wù)時,你應(yīng)該 永不 手動提交或回滾事務(wù)。 如果所有查詢都成功,但您仍然希望回滾事務(wù)(例如因為驗證失?。瑒t應(yīng)該拋出一個錯誤來斷開和拒絕鏈接:

return sequelize.transaction(function (t) {
  return User.create({
    firstName: 'Abraham',
    lastName: 'Lincoln'
  }, {transaction: t}).then(function (user) {
    // 查詢成功,但我們?nèi)匀幌牖貪L!
    throw new Error();
  });
});

自動將事務(wù)傳遞給所有查詢

在上面的例子中,事務(wù)仍然是手動傳遞的,通過傳遞 {transaction:t} 作為第二個參數(shù)。 要自動將事務(wù)傳遞給所有查詢,您必須安裝 continuation local storage (CLS) 模塊,并在您自己的代碼中實例化一個命名空間:

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

要啟用CLS,您必須通過使用sequelize構(gòu)造函數(shù)的靜態(tài)方法來告訴Sequelize要使用的命名空間:

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

new Sequelize(....);

請注意, useCLS() 方法在 構(gòu)造函數(shù) 上,而不是在 sequelize 的實例上。 這意味著所有實例將共享相同的命名空間,并且 CLS 是全部或全無方式 - 你不能僅在某些實例中啟用它。

CLS 的工作方式就像一個用于回調(diào)的本地線程存儲。 這在實踐中意味著不同的回調(diào)鏈可以通過使用 CLS 命名空間來訪問局部變量。 當(dāng)啟用 CLS 時,創(chuàng)建新事務(wù)時,Sequelize 將在命名空間上設(shè)置 transaction 屬性。 由于回調(diào)鏈中設(shè)置的變量對該鏈?zhǔn)撬接械?,因此可以同時存在多個并發(fā)事務(wù):

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

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

在大多數(shù)情況下,你不需要直接訪問 namespace.get('transaction'),因為所有查詢都將自動在命名空間中查找事務(wù):

sequelize.transaction(function (t1) {
  // 啟用 CLS 后,將在事務(wù)中創(chuàng)建用戶
  return User.create({ name: 'Alice' });
});

在使用 Sequelize.useCLS() 后,從 sequelize 返回的所有 promise 將被修補以維護 CLS 上下文。 CLS 是一個復(fù)雜的課題 - cls-bluebird的文檔中有更多細(xì)節(jié),用于使 bluebird promise 的補丁與CLS一起工作。

注意: 當(dāng)使用 cls-hooked 軟件包的時候,CLS 僅支持 async/await. 即使, cls-hooked 依靠 試驗性的 API async_hooks

并行/部分事務(wù)

你可以在一系列查詢中執(zhí)行并發(fā)事務(wù),或者將某些事務(wù)從任何事務(wù)中排除。 使用 {transaction: } 選項來控制查詢所屬的事務(wù):

警告: SQLite 不能同時支持多個事務(wù)。

不啟用CLS

sequelize.transaction(function (t1) {
  return sequelize.transaction(function (t2) {
    // 啟用CLS,這里的查詢將默認(rèn)使用 t2    
    // 通過 `transaction` 選項來定義/更改它們所屬的事務(wù)。
        return Promise.all([
        User.create({ name: 'Bob' }, { transaction: null }),
        User.create({ name: 'Mallory' }, { transaction: t1 }),
        User.create({ name: 'John' }) // 這將默認(rèn)為 t2
    ]);
  });
});

隔離等級

啟動事務(wù)時可能使用的隔離等級:

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"

默認(rèn)情況下,sequelize 使用數(shù)據(jù)庫的隔離級別。 如果要使用不同的隔離級別,請傳入所需級別作為第一個參數(shù):

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

  //  你的事務(wù)

  });

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

非托管事務(wù)(then-callback)

非托管事務(wù)強制您手動回滾或提交交易。 如果不這樣做,事務(wù)將掛起,直到超時。 要啟動非托管事務(wù),請調(diào)用 sequelize.transaction() 而不用 callback(你仍然可以傳遞一個選項對象),并在返回的 promise 上調(diào)用 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();
  });
});

參數(shù)

可以使用options對象作為第一個參數(shù)來調(diào)用transaction方法,這允許配置事務(wù)。

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

以下選項(使用默認(rèn)值)可用:

{
  autocommit: true,
  isolationLevel: 'REPEATABLE_READ',
  deferrable: 'NOT DEFERRABLE' // postgres 的默認(rèn)設(shè)置
}

在為 Sequelize 實例或每個局部事務(wù)初始化時,isolationLevel可以全局設(shè)置:

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

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

deferrable 選項在事務(wù)開始后觸發(fā)一個額外的查詢,可選地將約束檢查設(shè)置為延遲或立即。 請注意,這僅在PostgreSQL中受支持。

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

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

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

使用其他 Sequelize 方法

transaction 選項與其他大多數(shù)選項一起使用,通常是方法的第一個參數(shù)。
對于取值的方法,如 .create, .update(), .updateAttributes() 等。應(yīng)該傳遞給第二個參數(shù)的選項。
如果不確定,請參閱API文檔中的用于確定簽名的方法。

后提交 hook

transaction 對象允許跟蹤是否提交以及何時提交。

可以將 afterCommit hook 添加到托管和非托管事務(wù)對象:

sequelize.transaction(t => {
  t.afterCommit((transaction) => {
    // 你的邏輯片段
  });
});

sequelize.transaction().then(t => {
  t.afterCommit((transaction) => {
    // 你的邏輯片段
  });

  return t.commit();
})

傳遞給 afterCommit 的函數(shù)可以有選擇地返回一個承諾,在創(chuàng)建事務(wù)的承諾鏈解析之前這個承諾會被解析。

afterCommit 如果事務(wù)回滾,hook 不會 被提升。

afterCommit hook 不像標(biāo)準(zhǔn) hook, 不會 修改事務(wù)的返回值。

您可以將 afterCommit hook 與模型 hook 結(jié)合使用,以了解實例何時在事務(wù)外保存并可用

model.afterSave((instance, options) => {
  if (options.transaction) {
    // 在事務(wù)內(nèi)保存完成,等到事務(wù)被提交以通知監(jiān)聽器實例已被保存
    options.transaction.afterCommit(() => /* Notify */)
    return;
  }
  // 在事務(wù)之外保存完成,對于調(diào)用者來說可以安全地獲取更新后的模型通知
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容