为了清楚起见,autocommit 不仅打开/关闭事务,还会“提交”任何等待的查询。
<?php
mysqli_autocommit($link, FALSE); // 关闭自动提交
-一些查询 1;
-一些查询 2;
mysqli_commit($link); // 处理迄今为止的所有查询
-一些查询 3;
-一些查询 4;
mysqli_autocommit($link, TRUE); // 打开自动提交
?>
所有 4 个都将被处理。
(PHP 5、PHP 7、PHP 8)
mysqli::autocommit -- mysqli_autocommit — 打开或关闭数据库修改的自动提交
面向对象风格
过程化风格
打开或关闭数据库连接上查询的自动提交模式。
要确定自动提交的当前状态,请使用 SQL 命令 SELECT @@autocommit
。
如果启用了 mysqli 错误报告 (MYSQLI_REPORT_ERROR
) 并且请求的操作失败,则会生成警告。此外,如果模式设置为 MYSQLI_REPORT_STRICT
,则会抛出 mysqli_sql_exception。
示例 #1 mysqli::autocommit() 示例
面向对象风格
<?php
/* 如果发生错误,则告诉 mysqli 抛出异常 */
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
/* 表引擎必须支持事务 */
$mysqli->query("CREATE TABLE IF NOT EXISTS language (
Code text NOT NULL,
Speakers int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
/* 关闭自动提交 */
$mysqli->autocommit(false);
$result = $mysqli->query("SELECT @@autocommit");
$row = $result->fetch_row();
printf("Autocommit is %s\n", $row[0]);
try {
/* 准备插入语句 */
$stmt = $mysqli->prepare('INSERT INTO language(Code, Speakers) VALUES (?,?)');
$stmt->bind_param('ss', $language_code, $native_speakers);
/* 插入一些值 */
$language_code = 'DE';
$native_speakers = 50_123_456;
$stmt->execute();
$language_code = 'FR';
$native_speakers = 40_546_321;
$stmt->execute();
/* 提交数据库中的数据。这不会设置 autocommit=true */
$mysqli->commit();
print "Committed 2 rows in the database\n";
$result = $mysqli->query("SELECT @@autocommit");
$row = $result->fetch_row();
printf("Autocommit is %s\n", $row[0]);
/* 尝试插入更多值 */
$language_code = 'PL';
$native_speakers = 30_555_444;
$stmt->execute();
$language_code = 'DK';
$native_speakers = 5_222_444;
$stmt->execute();
/* 设置 autocommit=true 将触发提交 */
$mysqli->autocommit(true);
print "Committed 2 row in the database\n";
} catch (mysqli_sql_exception $exception) {
$mysqli->rollback();
throw $exception;
}
过程化风格
<?php
/* 指示 mysqli 在发生错误时抛出异常 */
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = mysqli_connect("localhost", "my_user", "my_password", "world");
/* 表引擎必须支持事务 */
mysqli_query($mysqli, "CREATE TABLE IF NOT EXISTS language (
Code text NOT NULL,
Speakers int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
/* 关闭自动提交 */
mysqli_autocommit($mysqli, false);
$result = mysqli_query($mysqli, "SELECT @@autocommit");
$row = mysqli_fetch_row($result);
printf("Autocommit is %s\n", $row[0]);
try {
/* 准备插入语句 */
$stmt = mysqli_prepare($mysqli, 'INSERT INTO language(Code, Speakers) VALUES (?,?)');
mysqli_stmt_bind_param($stmt, 'ss', $language_code, $native_speakers);
/* 插入一些值 */
$language_code = 'DE';
$native_speakers = 50_123_456;
mysqli_stmt_execute($stmt);
$language_code = 'FR';
$native_speakers = 40_546_321;
mysqli_stmt_execute($stmt);
/* 提交数据库中的数据。这不会设置 autocommit=true */
mysqli_commit($mysqli);
print "已提交数据库中的 2 行\n";
$result = mysqli_query($mysqli, "SELECT @@autocommit");
$row = mysqli_fetch_row($result);
printf("Autocommit is %s\n", $row[0]);
/* 尝试插入更多值 */
$language_code = 'PL';
$native_speakers = 30_555_444;
mysqli_stmt_execute($stmt);
$language_code = 'DK';
$native_speakers = 5_222_444;
mysqli_stmt_execute($stmt);
/* 设置 autocommit=true 将触发提交 */
mysqli_autocommit($mysqli, true);
print "已提交数据库中的 2 行\n";
} catch (mysqli_sql_exception $exception) {
mysqli_rollback($mysqli);
throw $exception;
}
以上示例将输出
Autocommit is 0 Committed 2 rows in the database Autocommit is 0 Committed 2 row in the database Autocommit is 0 Committed 2 rows in the database Autocommit is 0 Committed 2 row in the database
注意:
此函数不适用于非事务表类型(如 MyISAM 或 ISAM)。
为了清楚起见,autocommit 不仅打开/关闭事务,还会“提交”任何等待的查询。
<?php
mysqli_autocommit($link, FALSE); // 关闭自动提交
-一些查询 1;
-一些查询 2;
mysqli_commit($link); // 处理迄今为止的所有查询
-一些查询 3;
-一些查询 4;
mysqli_autocommit($link, TRUE); // 打开自动提交
?>
所有 4 个都将被处理。
值得注意的是,您可以使用标准 SQL 执行事务,而无需禁用自动提交。“START TRANSACTION;” 将启动事务。“COMMIT;” 将提交结果,“ROLLBACK;” 将恢复到事务前的状态。
CREATE TABLE 和 CREATE DATABASE(以及可能的其他命令)总是立即提交,并且您的事务似乎终止。因此,即使随后尝试回滚,之前和之后的任何命令都将被提交。
如果您处于事务的中间,并且您调用 mysqli_close(),则似乎您获得了隐式回滚的功能。
我无法重现下面概述的“代码错误导致锁定”问题(我总是获得成功的回滚,并且脚本将多次成功运行)。因此,我建议在 php-5.2.2 中已修复该问题。
我发现,如果 PHP 由于代码错误在事务期间退出,则 InnoDB 表可能会一直锁定,直到 Apache 重启。
简单的测试是通过设置 $mysqli_obj->autocommit(false) 并执行插入语句来启动事务。在到达 $mysqli_obj->commit 语句之前 - 让运行时代码错误炸毁 PHP。您检查数据库,没有发生插入(您假设发生了回滚).. 然后您修复错误,并再次尝试... 但是这次脚本大约需要 50 秒才能超时 - 插入语句返回“1205 - 锁等待超时;请尝试重新启动事务”。没有发生回滚。并且此错误将一直存在,直到您重新启动 Apache - 无论出于何种原因,资源都不会在进程被杀死之前释放。
我发现,与 PHP 代码错误相比,“退出”不会导致问题。因此,确实存在自动回滚机制 - 当 PHP 意外死亡时,它只是失败得很惨。不得不重启 Apache 是克服代码错误的一个非常极端的措施。
为了避免此问题,当启动事务时,我使用“register_shutdown_function()”,并设置一个标志以指示事务正在处理中(因为没有 unregister_shutdown_function())。请参见下文。因此,当脚本炸毁时,将调用 __shutdown_check() 例程(我相信它需要是公开的) - 它能够调用 rollback()。
这些只是相关的部分,让您了解一下...
<?php
public function begin_transaction() {
$ret = $this->mysqli_obj->autocommit(false);
$this->transaction_in_progress = true;
register_shutdown_function(array($this, "__shutdown_check"));
}
public function __shutdown_check() {
if ($this->transaction_in_progress) {
$this->rollback();
}
}
public function commit() {
$ret = $this->mysqli_obj->commit();
$this->transaction_in_progress = false;
}
public function rollback() {
$ret = $this->mysqli_obj->rollback();
$this->transaction_in_progress = false;
}
?>
适用于 PHP 5.1.6 及以上版本和 MySQL 5.0.24a 及以上版本。