PHP Conference Japan 2024

mysqli::autocommit

mysqli_autocommit

(PHP 5、PHP 7、PHP 8)

mysqli::autocommit -- mysqli_autocommit打开或关闭数据库修改的自动提交

描述

面向对象风格

public mysqli::autocommit(bool $enable): bool

过程化风格

mysqli_autocommit(mysqli $mysql, bool $enable): bool

打开或关闭数据库连接上查询的自动提交模式。

要确定自动提交的当前状态,请使用 SQL 命令 SELECT @@autocommit

参数

mysql

仅过程化风格:由 mysqli_connect()mysqli_init() 返回的 mysqli 对象

enable

是否打开自动提交。

返回值

成功时返回 true,失败时返回 false

错误/异常

如果启用了 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)。

参见

添加注释

用户贡献的注释 3 条注释

22
jcwebb at dicoe dot com
17 年前
为了清楚起见,autocommit 不仅打开/关闭事务,还会“提交”任何等待的查询。
<?php
mysqli_autocommit
($link, FALSE); // 关闭自动提交
-一些查询 1;
-
一些查询 2;
mysqli_commit($link); // 处理迄今为止的所有查询
-一些查询 3;
-
一些查询 4;
mysqli_autocommit($link, TRUE); // 打开自动提交
?>
所有 4 个都将被处理。
13
Geoffrey Thubron
17 年前
值得注意的是,您可以使用标准 SQL 执行事务,而无需禁用自动提交。“START TRANSACTION;” 将启动事务。“COMMIT;” 将提交结果,“ROLLBACK;” 将恢复到事务前的状态。

CREATE TABLE 和 CREATE DATABASE(以及可能的其他命令)总是立即提交,并且您的事务似乎终止。因此,即使随后尝试回滚,之前和之后的任何命令都将被提交。

如果您处于事务的中间,并且您调用 mysqli_close(),则似乎您获得了隐式回滚的功能。

我无法重现下面概述的“代码错误导致锁定”问题(我总是获得成功的回滚,并且脚本将多次成功运行)。因此,我建议在 php-5.2.2 中已修复该问题。
3
Glen
17 年前
我发现,如果 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 及以上版本。
To Top