为了清楚起见,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 "Committed 2 rows in the database\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 "Committed 2 row in the database\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 - 无论出于何种原因,资源都不会在进程被杀死之前释放。
我发现,"exit" 而不是 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。
如果您使用的是 mysql 命令行工具,以下是一些有关 autocommit 功能的提示
1. 要查看当前 autocommit 设置,可以使用以下查询:select @@autocommit; 它将以 1 或 0(开或关)的形式返回当前设置
2. 您可以在 my.cnf 或 my.ini 中管理默认 autocommit 功能,方法是在其中添加以下行:init_connect='set autocommit=0'。 我很确定这不在文档中,但它确实有效。
截至 MySQL 5.1dev,以下是支持事务的当前引擎
InnoDB
BerkeleyDB
Falcon
Falcon 非常新,因此请注意在生产系统上使用它。