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

開啟或關閉資料庫連線查詢的自動提交模式。

要判斷 autocommit 的目前狀態,請使用 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

/* Tell mysqli to throw an exception if an error occurs */
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

$mysqli = new mysqli("localhost", "my_user", "my_password", "world");

/* The table engine has to support transactions */
$mysqli->query("CREATE TABLE IF NOT EXISTS language (
Code text NOT NULL,
Speakers int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"
);

/* Turn autocommit off */
$mysqli->autocommit(false);

$result = $mysqli->query("SELECT @@autocommit");
$row = $result->fetch_row();
printf("Autocommit is %s\n", $row[0]);

try {
/* Prepare insert statement */
$stmt = $mysqli->prepare('INSERT INTO language(Code, Speakers) VALUES (?,?)');
$stmt->bind_param('ss', $language_code, $native_speakers);

/* Insert some values */
$language_code = 'DE';
$native_speakers = 50_123_456;
$stmt->execute();
$language_code = 'FR';
$native_speakers = 40_546_321;
$stmt->execute();

/* Commit the data in the database. This doesn't set 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]);

/* Try to insert more values */
$language_code = 'PL';
$native_speakers = 30_555_444;
$stmt->execute();
$language_code = 'DK';
$native_speakers = 5_222_444;
$stmt->execute();

/* Setting autocommit=true will trigger a commit */
$mysqli->autocommit(true);

print
"Committed 2 row in the database\n";
} catch (
mysqli_sql_exception $exception) {
$mysqli->rollback();

throw
$exception;
}

程序風格

<?php

/* Tell mysqli to throw an exception if an error occurs */
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

$mysqli = mysqli_connect("localhost", "my_user", "my_password", "world");

/* The table engine has to support transactions */
mysqli_query($mysqli, "CREATE TABLE IF NOT EXISTS language (
Code text NOT NULL,
Speakers int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"
);

/* Turn autocommit off */
mysqli_autocommit($mysqli, false);

$result = mysqli_query($mysqli, "SELECT @@autocommit");
$row = mysqli_fetch_row($result);
printf("Autocommit is %s\n", $row[0]);

try {
/* Prepare insert statement */
$stmt = mysqli_prepare($mysqli, 'INSERT INTO language(Code, Speakers) VALUES (?,?)');
mysqli_stmt_bind_param($stmt, 'ss', $language_code, $native_speakers);

/* Insert some values */
$language_code = 'DE';
$native_speakers = 50_123_456;
mysqli_stmt_execute($stmt);
$language_code = 'FR';
$native_speakers = 40_546_321;
mysqli_stmt_execute($stmt);

/* Commit the data in the database. This doesn't set 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]);

/* Try to insert more values */
$language_code = 'PL';
$native_speakers = 30_555_444;
mysqli_stmt_execute($stmt);
$language_code = 'DK';
$native_speakers = 5_222_444;
mysqli_stmt_execute($stmt);

/* Setting autocommit=true will trigger a commit */
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)。

參見

新增註解

使用者貢獻的註解 3 則註解

jcwebb at dicoe dot com
17 年前
需要說明的是,autocommit 不僅會開啟/關閉交易,還會「提交」任何等待中的查詢。
<?php
mysqli_autocommit
($link, FALSE); // 關閉自動提交
-一些查詢 1;
-
一些查詢 2;
mysqli_commit($link); // 處理目前為止的所有查詢
-一些查詢 3;
-
一些查詢 4;
mysqli_autocommit($link, TRUE); // 開啟自動提交
?>
所有 4 個查詢都會被處理。
Geoffrey Thubron
17 年前
值得注意的是,您可以使用標準 SQL 執行交易,而無需停用 autocommit。「START TRANSACTION;」將開始一個交易。「COMMIT;」將提交結果,而「ROLLBACK;」將恢復到交易前的狀態。

CREATE TABLE 和 CREATE DATABASE 指令(可能還有其他指令)都會立即提交,而且您的交易看似會終止。因此,之前和之後的任何指令都會被提交,即使後續嘗試了 rollback 也是一樣。

如果您在交易進行中呼叫 mysqli_close(),看起來您會得到隱式 rollback 的功能。

我無法重現下面描述的「程式碼錯誤導致鎖定」問題(我總是成功 rollback,而且腳本可以順利執行無數次)。因此,我認為該問題已在 php-5.2.2 中修復。
Glen
17 年前
我發現如果 PHP 因程式碼錯誤在交易過程中退出,InnoDB 資料表可能會保持鎖定狀態,直到重新啟動 Apache 為止。

簡單的測試方法是透過設定 $mysqli_obj->autocommit(false) 並執行 insert 陳述式來啟動交易。在執行 $mysqli_obj->commit 陳述式之前,讓程式碼錯誤導致 PHP 崩潰。您檢查資料庫,發現沒有插入任何資料(您假設發生了 rollback)…然後您去修復錯誤,並再次嘗試…但這次腳本花了大約 50 秒才逾時 — insert 陳述式返回「1205 - 鎖定等待逾時;請嘗試重新啟動交易」。沒有發生 rollback。而且這個錯誤在您重新啟動 Apache 之前不會消失 — 無論是什麼原因,資源直到進程被終止才會釋放。

我發現使用 `exit` 退出,而不是 PHP 程式碼錯誤,不會造成問題。所以有一個自動 rollback 機制 — 只是當 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