2016-05-31 125 views
17

PHP Documentation說:瞭解PDO MySQL的交易

如果你從來沒有遇到過的交易,他們提供了4個大 特點:原子性,一致性,隔離性和持久性(ACID)。在非專業人士的條件下,任何在交易中進行的工作,即使是分階段進行的 ,都會保證安全地應用於數據庫 ,並且在承諾時,不受其他連接的干擾。

問題:

這是否意味着我可以同時運行交易兩個獨立的PHP腳本沒有他們相互干擾?


詳細闡述了我的意思INTERFERING

假設我們有以下employees表:

__________________________ 
| id | name | salary | 
|------+--------+----------| 
| 1 | ana | 10000 | 
|------+--------+----------| 

如果我有兩個腳本具有類似/相同的代碼,他們在同一時間運行:

script1.phpscript2.php(兩者都具有相同的碼):

$conn->beginTransaction(); 

$stmt = $conn->prepare("SELECT * FROM employees WHERE name = ?"); 
$stmt->execute(['ana']); 
$row = $stmt->fetch(PDO::FETCH_ASSOC); 

$salary = $row['salary']; 
$salary = $salary + 1000;//increasing salary 

$stmt = $conn->prepare("UPDATE employees SET salary = {$salary} WHERE name = ?"); 
$stmt->execute(['ana']); 

$conn->commit(); 

並且假設事件的序列如下:

  • script1.php選擇數據

  • script2.php選擇數據

  • script1.php更新數據

  • script2.php更新數據

  • script1.php提交()發生

  • script2.php提交()發生

在這種情況下,ana的最終薪水是多少?

  • 會是11000嗎?那麼這是否意味着1次交易會與另一次交易重疊,因爲這些信息是在任何提交發生前獲得的?

  • 它會是12000嗎?那麼這是否意味着無論數據更新和選擇的順序如何,commit()函數都會迫使這些函數單獨發生?

請隨意詳細闡述事務和單獨腳本如何相互干擾(或不干擾)。

+0

我敢肯定的'SQLSTATE [23000]:完整性約束違規錯誤將彈出其中一個腳本。問題是如果他們都在同一時間運行哪一個。 – icecub

回答

13

你不會在php文檔中找到答案,因爲這與php或pdo無關。

mysql中的innodb表引擎提供了4個所謂的isolation levels符合sql標準。隔離級別連同阻塞/非阻塞讀取將決定上述示例的結果。您需要了解各種隔離級別的含義並根據您的需求選擇適當的隔離級別。總結一下:如果你使用關閉自動提交的可串行隔離級別,那麼結果將是12000.在所有其他隔離級別和啓用自動提交的情況下可串行化,結果將是11000.如果你開始使用鎖定讀取,那麼在所有隔離級別下的結果可能是12000。

7

根據給定的條件(一個單獨的DML語句)來判斷,這裏不需要事務,而是一個表鎖。這是一個非常普遍的混亂。

如果您需要確保您的所有DML語句都正確執行或根本沒有執行,則您需要一個事務。

手段

  • 你不需要交易,任意數量的SELECT查詢的
  • 如果只有一個DML語句執行

雖然你並不需要一個事務,正如Shadow在出色的回答中指出的那樣,您可能會在處使用具有適當隔離級別的事務,這樣會相當混亂。你需要的是table locking。 InnoDB引擎可以讓你lock particular rows而不是鎖定整個表,因此應該是首選。

如果您希望薪水爲1200,則使用表鎖。

或者 - 一個更簡單的方法 - 只要運行一個原子更新查詢:

UPDATE employees SET salary = salary + 1000 WHERE name = ? 

在這種情況下,所有的工資將被記錄。

如果您的目標不同,請更好地明確表達。

但是,您必須明白,一般的交易與單獨的腳本執行無關。關於你的話題競賽條件你有興趣不在交易,但在表/行鎖定。這是一個非常普遍的混亂,你最好直接瞭解它:

  • 事務是確保一個腳本成功執行中的DML查詢一組
  • 表/行鎖定是爲了確保其他腳本執行不會產生干擾。

交易和鎖定干擾的唯一的主題是deadlock,但同樣 - 只在交易使用鎖定的情況下。

+0

我認爲這個問題的目的是理解來自ACID的字母I,而不是以特定的方式執行特定的操作。至少這是我對它的解釋。我不同意你寫的關於表鎖的問題。在innodb中,您可以使用select語句執行行級鎖定,因此您不必鎖定整個表以最終獲得12000。我同意在上面的代碼中不需要選擇,因爲整個操作可以在一次更新中執行。但如果這只是一個旨在理解交易隔離的例子,那麼它就是爲了達到目的。 – Shadow

+0

我使用「表鎖」作爲一個通用術語,同時指出,使用innodb行級鎖定應該是首選。所以我假設你的評論是一個相當術語問題。關於問題的含義,我可能是理解問題的最佳人選,已經回答了15年。酸性問題是OP的一個XY問題,爲此他們剛剛遇到了研究其特定問題的問題。無論哪種方式,我認爲我們的答案都是相互印證,讓讀者更好。 –

4

唉,「無干擾」需要程序員的幫助。它需要BEGINCOMMIT來定義'交易'的範圍。並且...

你的例子不足。第一條聲明需要SELECT ... FOR UPDATE。這告訴交易處理,對於SELECT獲取的行可能有UPDATE。該警告對於「防止干擾」至關重要。現在時間軸讀取:

  • script1.php開始
  • script2.php開始
  • script1.php選擇數據(FOR UPDATE
  • script2.php選擇數據被阻斷,所以它等待
  • script1.php更新數據
  • script1.php commit()發生
  • script2.php選擇數據(並將獲得新提交的值)
  • script2.php更新數據
  • script2.php提交()發生

(注:這是不是一個 '僵局',只是一個 '等待'。)