📜  laravel 中的事务提交回滚 - PHP (1)

📅  最后修改于: 2023-12-03 15:17:13.342000             🧑  作者: Mango

Laravel 中的事务提交回滚 - PHP

在 Laravel 中,我们可以利用事务来确保多个数据库操作的原子性。通过事务,我们可以提交多个操作,并且一旦其中任何一个操作失败,整个事务都会回滚到最初状态。本文将介绍 Laravel 中如何实现事务的提交和回滚。

开始一个事务

要开始一个事务,我们可以使用 DB Facade 提供的 transaction 方法。例如,我们可以在一个控制器方法中开始一个事务,并在此事务中插入一些数据:

public function store(Request $request)
{
    DB::beginTransaction();

    try {
        // 在此处插入数据
        DB::table('users')->insert([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);

        DB::commit();

        return redirect('/users');
    } catch (\Exception $e) {
        DB::rollback();

        return back()->withError($e->getMessage());
    }
}

在上面的代码中,我们使用了两个关键方法:

  • beginTransaction:开启事务。这个方法会创建一个数据库事务,并将数据库的隔离级别设置为 READ_COMMITTED
  • commit:提交事务。当我们执行多个数据库操作时,只有所有操作均执行成功时,我们才会调用 commit 方法。

如果任何操作失败,我们将回滚整个事务,这是通过调用 rollback 方法实现的。

回滚事务

如果在事务中的任何时刻出现了错误,我们可以通过回滚事务来撤销整个事务。这时,事务中的数据将永久性地删除,而不是停留在数据库中。

我们可以通过 try/catch 块和 rollback 方法来回滚事务。在 Laravel 中,如果任何数据库操作引发了异常,该异常将传递到 catch 块并由该块处理。我们可以利用这个机制来回滚整个事务。

public function update(Request $request, $id)
{
    DB::beginTransaction();

    try {
        DB::table('users')->where('id', $id)->update([
            'name' => $request->name,
            'email' => $request->email,
        ]);

        DB::commit();

        return redirect('/users');
    } catch (\Exception $e) {
        DB::rollback();

        return back()->withError($e->getMessage());
    }
}

在上面的代码中,我们在 try 块中进行了数据库更新操作,如果出现异常,我们回滚整个事务并返回错误信息。如果没有任何异常,我们提交事务并将用户重定向到用户列表页面。

手动回滚事务

除了通过 try/catch 块手动回滚事务之外,我们还可以使用 DB Facade 提供的 rollBack 方法手动回滚事务。例如:

public function destroy($id)
{
    DB::beginTransaction();

    try {
        DB::table('users')->where('id', $id)->delete();

        DB::commit();

        return redirect('/users');
    } catch (\Exception $e) {
        DB::rollback();

        return back()->withError($e->getMessage());
    }
}

在上面的代码中,我们在 try 块中进行了数据库删除操作,如果出现异常,我们回滚整个事务并返回错误信息。如果没有任何异常,我们提交事务并将用户重定向到用户列表页面。

创建保存点

在 Laravel 中,我们还可以使用 savepoint 来创建保存点(Savepoint)。保存点是事务的中间状态,允许我们先执行一部分操作,然后在后面的操作中检查错误。如果后面的操作失败,我们可以回滚到保存点并重试,而不是回滚整个事务。

要创建保存点,我们可以使用 DB Facade 提供的 beginTransaction 方法的可选参数 $name。例如:

public function transfer(Request $request)
{
    DB::beginTransaction('transfer');

    try {
        $from_account = DB::table('accounts')->where('id', $request->from_id)->lockForUpdate()->first();

        $to_account = DB::table('accounts')->where('id', $request->to_id)->lockForUpdate()->first();

        $amount = $request->amount;

        if ($from_account->balance < $amount) {
            throw new \Exception("Insufficient funds");
        }

        DB::table('accounts')->where('id', $request->from_id)->decrement('balance', $amount);

        DB::table('accounts')->where('id', $request->to_id)->increment('balance', $amount);

        DB::commit();

        return redirect('/accounts');
    } catch (\Exception $e) {
        DB::rollBack('transfer');

        return back()->withError($e->getMessage());
    }
}

在上面的代码中,我们在 beginTransaction 方法中指定了 transfer 作为保存点的名称。如果我们需要回滚到该保存点,我们可以使用 rollBack 方法,并且指定要回滚到的保存点名称。在 try 块中,我们执行了一系列数据库操作,如果任何操作失败,我们回滚到保存点 transfer 并返回错误信息。

结论

在 Laravel 中,事务是确保多个数据库操作的原子性的最重要的机制之一。在编写涉及多个数据库操作的代码时,请始终使用事务来确保数据的一致性和完整性。