NodeJS的sequelize的事务2

429 阅读2分钟

这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战

并发或部分事务

可以在一系列查询中进行并发事务,也可以将某些事务排除在任何事务之外, 使用 transaction 参数来控制查询属于哪个事务:

注意一下SQLite, 不支持同时多个事务.*

启用 CLS

sequelize.transaction((t1) => {
  return sequelize.transaction((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 方法接受参数.

对于非托管事务,只需使用 sequelize.transaction(options).

对于托管交易,请使用 sequelize.transaction(options, callback).

隔离级别

启动事务时可能使用的隔离级别:

const { Transaction } = require('sequelize');

// 以下是有效的隔离级别:
Transaction.ISOLATION_LEVELS.READ_UNCOMMITTED // "READ UNCOMMITTED"
Transaction.ISOLATION_LEVELS.READ_COMMITTED // "READ COMMITTED"
Transaction.ISOLATION_LEVELS.REPEATABLE_READ  // "REPEATABLE READ"
Transaction.ISOLATION_LEVELS.SERIALIZABLE // "SERIALIZABLE"

默认情况下, sequelize 使用数据库的隔离级别. 如果要使用其他隔离级别,传入所需的级别作为第一个参数:

const { Transaction } = require('sequelize');

await sequelize.transaction({
  isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE
}, async (t) => {
  // 你的代码
});

可以使用 Sequelize 构造函数中的一个参数来全局覆盖 isolationLevel 设置

const { Sequelize, Transaction } = require('sequelize');

const sequelize = new Sequelize('sqlite::memory:', {
  isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE
});

注意一下MSSQL, 因为指定的 isolationLevel 被直接传递给 tedious ,所以没有记录 SET ISOLATION LEVEL 查询

如果与其他 sequelize 方法一起使用

transaction 参数与大多数其他参数一起使用,通常是方法的第一个参数.

对于带有值的方法, 例如 .create,.update() 等.transaction 应该传递给第二个参数.

await User.create({ name: 'Foo Bar' }, { transaction: t });

await User.findAll({
  where: {
    name: 'Foo Bar'
  },
  transaction: t
});

afterCommit hook

一个 transaction 对象可以允许跟踪它是否以及何时被提交

可以将 afterCommit hook 添加到托管和非托管事务对象中

// 托管事务:
await sequelize.transaction(async (t) => {
  t.afterCommit(() => {
    // 你的代码
  });
});

// 非托管事务:
const t = await sequelize.transaction();
t.afterCommit(() => {
  // 你的代码
});
await t.commit();

传递给 afterCommit 的回调可以是 async

  • 对于托管交易:sequelize.transaction 调用将在完成之前等待它;
  • 对于非托管交易:t.commit 调用将在完成之前等待它.

注意:

  • 如果事务回滚,则不会引发 afterCommit hook;
  • afterCommit hook 不修改事务的返回值(与大多数 hook 不同)

可以将 afterCommit hook 与模型 hook 结合使用,以了解何时保存实例并在事务外部可用