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