2024 年日本 PHP 研討會

交易與自動提交

透過 PDO 連線後,在開始發出查詢之前,您必須了解 PDO 如何管理交易。如果您以前從未接觸過交易,它們提供四大特性:原子性、一致性、隔離性和持久性 (ACID)。簡而言之,在交易中執行的任何工作,即使是分階段執行,都能保證在提交時安全地應用於資料庫,且不受其他連線的干擾。交易工作也可以根據您的要求自動撤銷(前提是您尚未提交),這讓您的腳本更容易處理錯誤。

交易通常是透過「累積」一批變更,然後一次性套用來實現的;這樣做有一個很好的副作用,就是可以大幅提升這些更新的效率。換句話說,交易可以讓您的腳本執行得更快,也可能更穩健(您仍然需要正確地使用它們才能獲得這個好處)。

遺憾的是,並非所有資料庫都支援交易,因此 PDO 在您第一次開啟連線時需要以所謂的「自動提交」模式執行。自動提交模式表示您執行的每個查詢都有其隱含的交易(如果資料庫支援的話),或者如果資料庫不支援交易則沒有交易。如果您需要一個交易,則必須使用 PDO::beginTransaction() 方法來啟動一個。如果底層驅動程式不支援交易,則會拋出 PDOException(無論您的錯誤處理設定為何:這始終是一種嚴重的錯誤狀況)。一旦您處於交易中,您可以使用 PDO::commit()PDO::rollBack() 來完成它,取決於您在交易期間執行的程式碼是否成功。

警告

PDO 僅在驅動程式層級檢查交易功能。如果某些執行時條件意味著交易不可用,PDO::beginTransaction() 仍然會在資料庫伺服器接受啟動交易的請求時,無錯誤地返回 true

這種情況的一個例子是在 MySQL 資料庫的 MyISAM 資料表上嘗試使用交易。

當腳本結束或連線即將關閉時,如果您有一個未完成的交易,PDO 會自動將其回滾。這是一項安全措施,有助於避免腳本意外終止時出現不一致的情況——如果您沒有明確提交交易,則假設出現了問題,因此為了資料安全會執行回滾。

警告

自動回滾僅在您透過 PDO::beginTransaction() 啟動交易時才會發生。如果您手動發出開始交易的查詢,PDO 無法知道它,因此如果發生錯誤,就無法將其回滾。

範例 #1 在交易中執行批次

在以下範例中,假設我們正在為一位新員工建立一組條目,該員工的 ID 編號為 23。除了輸入該人員的基本資料外,我們還需要記錄他們的薪資。進行兩次單獨的更新非常簡單,但是透過將它們包含在 PDO::beginTransaction()PDO::commit() 呼叫中,我們可以保證沒有其他人能夠在這些變更完成之前看到它們。如果出現問題,catch 區塊會回滾自交易啟動以來所做的所有變更,然後印出錯誤訊息。

<?php
try {
$dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2',
array(
PDO::ATTR_PERSISTENT => true));
echo
"已連線\n";
} catch (
Exception $e) {
die(
"無法連線: " . $e->getMessage());
}

try {
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$dbh->beginTransaction();
$dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
$dbh->exec("insert into salarychange (id, amount, changedate)
values (23, 50000, NOW())"
);
$dbh->commit();

} catch (
Exception $e) {
$dbh->rollBack();
echo
"失敗: " . $e->getMessage();
}
?>

您在事務中不只可以進行更新;您也可以發出複雜的查詢來提取資料,並可能使用該資訊來建構更多更新和查詢;當事務處於活動狀態時,可以保證沒有其他人可以在您工作期間進行更改。有關事務的更多資訊,請參閱您的資料庫伺服器提供的文件。

新增註解

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

hooby404 at gmail dot com
2 年前
> 您在事務中不只可以進行更新;您也可以發出複雜的
> 查詢來提取資料,並可能使用該資訊來建構更多更新
> 和查詢;當事務處於活動狀態時,可以保證沒有其他人可以在您
> 工作期間進行更改。有關事務
> 的更多資訊,請參閱您的資料庫伺服器提供的文件。

只有在您明確執行「SELECT .... FOR UPDATE」時,這才成立。

如果沒有「FOR UPDATE」子句,當兩個交易同時執行時,第二個交易可能會在第一個交易讀取值之後,但在第一個交易使用該值進行更新之前更改它。

如果沒有「FOR UPDATE」子句,您絕對無法保證在您處理過程中沒有其他人可以進行更改。
harl at gmail dot com
6 年前
有些資料庫管理系統 (DBMS) 允許在交易中使用資料定義語言 (DDL)(例如建立/修改表格),有些則不允許。詢問「我的 DBMS 是否允許在交易中使用 DDL 而不強制提交?」會得到以下範例答案:

CUBRID:允許
DB2 UDB:允許
Firebird:允許
Informix:允許
MySQL:不允許
Oracle:不允許(儘管可以使用「基於版本的重新定義」來推出結構描述升級)
PostgreSQL:允許
SQLite:允許
SQL Server:視隔離等級、指令類型等而定
Sybase:允許
pasamio at gmail dot com
12 年前
通常,資料定義語言子句 (DDL) 會觸發資料庫引擎自動提交。
https://mysqldev.dev.org.tw/doc/refman/5.0/en/implicit-commit.html

許多其他資料庫(例如 Oracle)會在執行 DDL 陳述式之前和之後隱式提交。
To Top