Skip to main content

数据库事务

🌐 Database transactions

Page summary:

数据库事务将多个操作组合在一起,使它们作为一个整体成功或回滚。实验性的 strapi.db.transaction 辅助工具提供 trx、提交和回滚功能,用于封装的服务调用。

Caution

这是一个实验性功能,可能会在未来版本中发生变化。

🌐 This is an experimental feature and is subject to change in future versions.

Strapi 5 提供一个 API 来将一组操作封装在一个事务中,以确保数据的完整性。

🌐 Strapi 5 provide an API to wrap a set of operations in a transaction that ensures the integrity of data.

事务是一组作为单一单元一起执行的操作。如果其中任何操作失败,整个事务将失败,数据会回滚到之前的状态。如果所有操作都成功,事务将提交,数据将永久保存到数据库中。

🌐 Transactions are a set of operations that are executed together as a single unit. If any of the operations fail, the entire transaction fails and the data is rolled back to its previous state. If all operations succeed, the transaction is committed and the data is permanently saved to the database.

使用

🌐 Usage

事务通过将处理函数传入 strapi.db.transaction 来处理:

🌐 Transactions are handled by passing a handler function into strapi.db.transaction:

await strapi.db.transaction(async ({ trx, rollback, commit, onCommit, onRollback }) => {
// It will implicitly use the transaction
await strapi.entityService.create();
await strapi.entityService.create();
});

在事务处理程序执行后,如果所有操作都成功,则事务会被提交。如果任何操作抛出异常,事务将被回滚,数据会恢复到之前的状态。

🌐 After the transaction handler is executed, the transaction is committed if all operations succeed. If any of the operations throws, the transaction is rolled back and the data is restored to its previous state.

Note

在事务块中执行的每个 strapi.entityServicestrapi.db.query 操作将隐式使用该事务。

🌐 Every strapi.entityService or strapi.db.query operation performed in a transaction block will implicitly use the transaction.

事务处理器属性

🌐 Transaction handler properties

处理程序函数接收具有以下属性的对象:

🌐 The handler function receives an object with the following properties: | 属性 | 描述 || --- | --- || trx | 事务对象。它可以用来在事务中执行 knex 查询。 || commit | 提交事务的函数。 || rollback | 回滚事务的函数。 || onCommit | 注册一个在事务提交后执行的回调函数的函数。 || onRollback | 注册一个在事务回滚后执行的回调函数的函数。 |

嵌套事务

🌐 Nested transactions

事务可以嵌套。当事务嵌套时,内层事务会在外层事务提交或回滚时被提交或回滚。

🌐 Transactions can be nested. When a transaction is nested, the inner transaction is committed or rolled back when the outer transaction is committed or rolled back.

await strapi.db.transaction(async () => {
// It will implicitly use the transaction
await strapi.entityService.create();

// Nested transactions will implicitly use the outer transaction
await strapi.db.transaction(async ({}) => {
await strapi.entityService.create();
});
});

在提交时和在回滚时

🌐 onCommit and onRollback

onCommitonRollback 钩子可以用来在事务提交或回滚后执行代码。

🌐 The onCommit and onRollback hooks can be used to execute code after the transaction is committed or rolled back.

await strapi.db.transaction(async ({ onCommit, onRollback }) => {
// It will implicitly use the transaction
await strapi.entityService.create();
await strapi.entityService.create();

onCommit(() => {
// This will be executed after the transaction is committed
});

onRollback(() => {
// This will be executed after the transaction is rolled back
});
});

使用 knex 查询

🌐 Using knex queries

事务也可以与 knex 查询一起使用,但在这些情况下必须显式调用 .transacting(trx)

🌐 Transactions can also be used with knex queries, but in those cases .transacting(trx) must be explicitly called.

await strapi.db.transaction(async ({ trx, rollback, commit }) => {
await knex('users').where('id', 1).update({ name: 'foo' }).transacting(trx);
});

何时使用事务

🌐 When to use transactions

在需要多次操作一起执行并且它们的执行相互依赖的情况下,应使用事务。例如,在创建新用户时,应该在数据库中创建用户,并向用户发送欢迎邮件。如果邮件发送失败,则不应在数据库中创建用户。

🌐 Transactions should be used in cases where multiple operations should be executed together and their execution is dependent on each other. For example, when creating a new user, the user should be created in the database and a welcome email should be sent to the user. If the email fails to send, the user should not be created in the database.

何时不使用事务

🌐 When not to use transactions

事务不应用于不相互依赖的操作,因为它可能导致性能损失。

🌐 Transactions should not be used for operations that are not dependent on each other since it can result in performance penalties.

事务的潜在问题

🌐 Potential problems of transactions

在事务内执行多个操作可能会导致锁定,这可能会阻止其他进程执行事务,直到原始事务完成。

🌐 Performing multiple operations within a transaction can lead to locking, which can block the execution of transactions from other processes until the original transaction is complete.

此外,如果事务未正确提交或回滚,则可能会停滞。

🌐 Furthermore, transactions can stall if they are not committed or rolled back appropriately.

例如,如果一个事务被打开,但你的代码中有一条路径没有关闭它,事务将会无限期地保持打开状态,并可能导致不稳定,直到你的服务器被重启并且连接被强制关闭。这些问题可能很难调试,因此在必要的情况下使用事务时要谨慎。

🌐 For example, if a transaction is opened but there is a path in your code that does not close it, the transaction will be left open indefinitely and could cause instability until your server is restarted and the connection is forced to close. These issues can be difficult to debug, so use transactions with care in the cases they are necessary.