事务

CodeIgniter 的数据库抽象允许您对支持事务安全表类型的数据库使用事务。在 MySQL 中,您需要运行 InnoDB 或 BDB 表类型,而不是更常见的 MyISAM。大多数其他数据库平台都原生支持事务。

如果您不熟悉事务,我们建议您找到一个好的在线资源来了解您特定数据库的事务。以下信息假设您对事务有基本了解。

CodeIgniter 的事务方法

CodeIgniter 使用的事务方法与流行的数据库类 ADODB 使用的方法非常相似。我们选择这种方法是因为它极大地简化了运行事务的过程。在大多数情况下,只需要两行代码。

传统上,事务需要相当多的工作才能实现,因为它们要求您跟踪您的查询,并根据查询的成功或失败来确定是提交还是回滚。对于嵌套查询来说,这尤其麻烦。相反,我们实现了一个智能事务系统,它会自动为您完成所有这些工作(您也可以选择手动管理您的事务,但实际上没有好处)。

注意

从 v4.3.0 开始,在事务期间,即使 DBDebug 为 true,也不会默认抛出异常。

运行事务

要使用事务运行查询,可以使用 $this->db->transStart()$this->db->transComplete() 方法,如下所示

<?php

$this->db->transStart();
$this->db->query('AN SQL QUERY...');
$this->db->query('ANOTHER QUERY...');
$this->db->query('AND YET ANOTHER QUERY...');
$this->db->transComplete();

您可以在 transStart()/transComplete() 方法之间运行任意数量的查询,它们将根据任何给定查询的成功或失败而全部提交或回滚。

严格模式

默认情况下,CodeIgniter 在严格模式下运行所有事务。启用严格模式后,如果您正在运行多个事务组,如果一个组失败,所有后续组将回滚。如果禁用严格模式,则每个组将被独立对待,这意味着一个组的失败不会影响任何其他组。

严格模式可以按如下方式禁用

<?php

$this->db->transStrict(false);

管理错误

当您在 app/Config/Database.php 文件中将 DBDebug 设置为 true 时,如果发生查询错误,所有查询将回滚,并且会抛出异常。因此,您将看到一个标准错误页面。

如果 DBDebug 为 false,您可以像这样管理自己的错误

<?php

$this->db->transStart();
$this->db->query('AN SQL QUERY...');
$this->db->query('ANOTHER QUERY...');
$this->db->transComplete();

if ($this->db->transStatus() === false) {
    // generate an error... or use the log_message() function to log your error
}

抛出异常

版本 4.3.0 中的新增功能。

注意

从 v4.3.0 开始,在事务期间,即使 DBDebug 为 true,也不会默认抛出异常。

如果您希望在发生查询错误时抛出异常,可以使用 $this->db->transException(true)

<?php

// When DBDebug in the Database Config must be true.

use CodeIgniter\Database\Exceptions\DatabaseException;

try {
    $this->db->transException(true)->transStart();
    $this->db->query('AN SQL QUERY...');
    $this->db->query('ANOTHER QUERY...');
    $this->db->query('AND YET ANOTHER QUERY...');
    $this->db->transComplete();
} catch (DatabaseException $e) {
    // Automatically rolled back already.
}

如果发生查询错误,所有查询将回滚,并且会抛出 DatabaseException

禁用事务

事务默认情况下是启用的。如果您想禁用事务,可以使用 $this->db->transOff()

<?php

$this->db->transOff();
$this->db->transStart();
$this->db->query('AN SQL QUERY...');
$this->db->transComplete();

禁用事务后,您的查询将自动提交,就像在没有事务的情况下运行查询一样。

测试模式

您可以选择将事务系统置于“测试模式”,这将导致您的查询被回滚,即使查询产生了有效的结果。要使用测试模式,只需将 $this->db->transStart() 方法中的第一个参数设置为 true 即可。

<?php

$this->db->transStart(true); // Query will be rolled back
$this->db->query('AN SQL QUERY...');
$this->db->transComplete();

手动运行事务

当您在 app/Config/Database.php 文件中将 DBDebug 设置为 false 时,如果您想手动运行事务,可以按照以下步骤进行。

<?php

$this->db->transBegin();

$this->db->query('AN SQL QUERY...');
$this->db->query('ANOTHER QUERY...');
$this->db->query('AND YET ANOTHER QUERY...');

if ($this->db->transStatus() === false) {
    $this->db->transRollback();
} else {
    $this->db->transCommit();
}

注意

在运行手动事务时,请确保使用 $this->db->transBegin(),**而不是** $this->db->transStart()

嵌套事务

在 CodeIgniter 中,事务可以嵌套,这样只有最外层或顶层的事务命令会被执行。您可以在事务块中包含任意数量的 transStart()/transComplete()transBegin()/transCommit()/transRollback() 对,依此类推。CodeIgniter 会跟踪事务的“深度”,并且只在最外层(深度为零)采取行动。

<?php

$this->db->transStart(); // actually starts a transaction
$this->db->query('SOME QUERY 1 ...');
$this->db->transStart(); // doesn't necessarily start another transaction
$this->db->query('SOME QUERY 2 ...');
$this->db->transComplete(); // doesn't necessarily end the transaction, but required to finish the inner transaction
$this->db->query('SOME QUERY 3 ...');
$this->db->transComplete(); // actually ends the transaction

注意

如果结构更加复杂,您有责任确保内部事务能够再次到达最外层,以便被数据库完全执行,从而防止意外提交/回滚。