跳至内容

事务

数据库事务是一系列读/写操作,这些操作保证要么全部成功,要么全部失败。在本章中,我们将介绍

交互式事务

使用 $transaction 方法在事务中执行闭包。如果闭包中的任何操作失败,整个事务将回滚

dart
/// Transfer views from one post to another
transfer(int from, int to, int views) async {
  await prisma.$transaction((tx) async {
    // 1. Decrement views from the source post
    await tx.post.update(
      where: PostWhereUniqueInput(id: from),
      data: PrismaUnion.$1(
        PostUpdateInput(
          views: PrismaUnion.$2(
            IntFieldUpdateOperationsInput(decrement: views),
          ),
        ),
      ),
    );

    // 2. Increment views from the destination post
    await tx.post.update(
      where: PostWhereUniqueInput(id: to),
      data: PrismaUnion.$1(
        PostUpdateInput(
          views: PrismaUnion.$2(
            IntFieldUpdateOperationsInput(increment: views),
          ),
        ),
      ),
    );
  });
}

await transfer(1, 2, 10); // Transfer 10 views from post 1 to post 2
await transfer(2, 1, 10); // Transfer 10 views from post 2 to post 1

在上面的示例中,您可以尝试传递无效数据到 transfer,因为任何抛出的异常都将导致事务回滚,而不会影响数据。

捕获异常/错误

您有时可能希望在事务中捕获异常或错误。您可以使用 try/catch 语句来实现

dart
try {
  await prisma.$transaction((tx) async {
    // Code running in a transaction...
  });
} catch (e) {
  // Handle the rollback...
}

隔离级别

Prisma Dart 客户端事务支持隔离级别(如果数据库支持)。默认情况下,事务使用数据库的默认隔离级别。要更改隔离级别,请使用 isolationLevel 参数

dart
await prisma.$transaction(
  isolationLevel: TransactionIsolationLevel.serializable, 
  (tx) async {
    // Code running in a transaction...
  },
);

支持的数据库隔离级别矩阵

数据库未提交读已提交读可重复读序列化快照
PostgreSQL
MySQL
SQL Server
CockroachDB
SQLite

默认隔离级别

PostgresSQLMySQLSQL ServerCockroachDBSQLite
已提交读可重复读已提交读序列化序列化

警告

TransactionIsolationLevel 枚举公开了 Prisma Dart 客户端支持的所有隔离级别。但是,并非所有数据库都支持所有隔离级别。例如,SQLite 仅支持 Serializable 隔离级别。

有关隔离级别的数据库特定信息

请参阅以下资源

超时

当您使用交互式事务时,为了避免长时间等待,您可以通过以下两个参数设置事务运行时间

  • maxWait - 客户端等待数据库事务的最长时间,默认为 2
  • timeout - 交互式事务在被取消或回滚之前可以运行的最长时间,默认为 5
dart
await prisma.$transaction(
  (tx) async {
    // Code running in a transaction...
  },
  maxWait: 5000, // Default is 2000
  timeout: 10000, // Default is 5000
);

警告

您应该谨慎使用 timeout 参数,长时间保持事务打开会损害数据库性能,甚至可能导致死锁。尝试避免在事务函数中执行网络请求和性能较慢的查询。我们建议尽快进入和退出!

手动事务

Prisma Dart 客户端支持手动事务,这意味着您可以在事务中执行任意数量的操作,然后决定是提交还是回滚事务。

dart
final tx = await prisma.$transaction.start(); 
try {
  // Delete all posts
  await tx.post.deleteMany();
  // Delete all users
  await tx.user.deleteMany();

  // Commit the transaction
  await tx.$transaction.commit(); 
} catch (e) {
  // Rollback the transaction
  await tx.$transaction.rollback(); 
}

使用 $transaction.start() 将返回一个新的 PrismaClient 实例。事务中的所有操作都应在此实例上执行。当您决定提交或回滚事务时,请调用 $transaction.commit()$transaction.rollback()

根据 BSD-3-Clause 许可证发布