客戶端提交提交語句,並收到一條消息,指出通信失敗。出現這種類型的故障有幾個原因,包括數據庫實例故障或網絡中斷。在這種情況下,客戶端不知道事務的狀態。如何InnoDB的決心飛行交易?
如何InnoDB的解決這樣的飛行交易? 交易是成功還是失敗?
客戶端提交提交語句,並收到一條消息,指出通信失敗。出現這種類型的故障有幾個原因,包括數據庫實例故障或網絡中斷。在這種情況下,客戶端不知道事務的狀態。如何InnoDB的決心飛行交易?
如何InnoDB的解決這樣的飛行交易? 交易是成功還是失敗?
從InnoDB的角度來看,一個事務正在運行或不。如果沒有,它已被提交或回滾。
從客戶端的角度來看,這確實是一個不明確的情況。
客戶端恢復會話是不可能的,因爲導致條件嚴重的網絡錯誤的定義也嚴重到足以使會話(即擁有該事務的數據庫連接)不可恢復。
如果服務器收到的提交,並用OK包迴應,但網絡錯誤從接收到OK防止客戶端,然後在錯誤發生之前事務提交。向客戶端發送OK數據包的網絡錯誤預計會強制關閉連接,但事務已被提交,所以它當然會保留。
在另一方面,如果網絡的錯誤到達服務器防止客戶端的COMMIT
消息,則兩種狀態是可能的:
網絡誤差也導致TCP連接到服務器被關閉從服務器的角度來看 - 在這種情況下,交易立即回滾;或
網絡錯誤沒有導致TCP連接到服務器被關閉,例如,如果有狀態網絡設備失去了它的狀態表可能是這種情況。在這種情況下,連接將不可用並且不可恢復。該連接沒有進一步的業務 - 無論是正版還是由網絡基礎設施欺騙 - 可能會被服務器接受,所以交易仍然未提交的,跑步,抱着什麼鎖可能已經舉行,因爲服務器是,首先,不知道客戶事實上已經消失了。當服務器超時客戶端連接或服務器主機上的IP堆棧強制連接發生錯誤時,事務將回滾,因爲TCP保持活動失敗。
這兩種情況都會立即回滾事務,最終會一次回滾事務。
如果之前的錯誤,客戶端就已經意識到它的連接標識符(SELECT CONNECTION_ID()
)的,如果連接然後恢復,它可以重新連接到服務器和查詢內部INFORMATION_SCHEMA
的PROCESSLIST
和INNODB_TRX
表,以發現是否其以前的連接仍然存在,並且連接是否有正在運行的事務。
如果舊的連接仍然存在,且具有交易運行時,交易沒有提交。應該使用KILL [connection_id]
殺死舊線程,以便事務立即回滾。
如果舊連接仍然存在,並且沒有正在運行的事務,則提交成功,因爲如果連接仍然存在,則沒有其他原因會丟失事務,因爲服務器不知道的網絡錯誤(否則連接將會消失)。
如果舊的連接不存在,前一個事務的狀態是未知的,除了我們知道它不能繼續運行;它可能已經提交或可能已經回滾。在保留了上一次交易中收集的其他信息(例如已分配的自動增量值)後,客戶可以啓發式地確定交易是否已完成。
但這種積極的後續一種罕見的發生似乎有些過度了許多環境中,類似這樣的回覆就足夠(一個Web「我們很抱歉,您訂貨出了錯」站點)或500 Internal Server Error
可能足夠用於API。
在API的情況下,冪等標記有時用於允許調用者安全地重試失敗模糊的操作。
例如,考慮Amazon EC2「運行實例」API。 (這與問題沒有直接關係,但它是我想要說明的行爲的一個詳盡記錄的示例,即使您不使用或不熟悉Amazon EC2,原則上也應該有意義)。這個API允許你啓動虛擬機,這當然會花費你的錢。如果在嘗試啓動機器時遇到網絡超時,該怎麼辦?那麼500 Internal Server Error
響應呢?你應該再問一次嗎?你現在是否有兩臺虛擬機,支付的金額是預期的兩倍?不,你不會,因爲那個API supports an idempotent token。這個令牌讓您可以再次嘗試 - 如果您使用相同的標記來製作語義相同的請求 - 而不會被誤解爲想要啓動兩臺計算機。當他們試圖處理你的請求時,他們檢查他們是否已經用相同的標記處理了一個請求。如果他們有,並且如果這是對同一件事的請求,他們會返回他們打算第一次返回的相同成功響應,因爲無論出於何種原因,您都不應該看到響應。同樣,兩個相同的請求與兩個不同的標記都被非正式地解釋爲意味着你確實想要啓動兩臺機器。
您可以使用唯一的鍵約束和唯一標識符(如UUID)在MySQL數據庫中完成類似的操作,您可以在事務正在執行(或重試)時插入該UUID。
如果在您重新連接並重試時使用該唯一ID修改的表中有一行,則知道該事務實際上已提交(假設您使用的隔離級別爲READ COMMITTED
或更高)。
如果該行不存在,則知道事務已回退 - 或者在服務器尚未意識到連接已被放棄的情況下將回滾。如果其他事務仍在運行,那麼該行看起來並不存在(也許取決於您的隔離級別 - 您可能會看到它),但是當您嘗試重複插入時,您的事務應該阻止,因爲原始(仍在運行但註定失敗)事務在唯一索引中的行上存在衝突排他鎖。嘗試將重複行插入唯一鍵將阻塞,直到釋放衝突鎖,此時插入將成功,如果沒有違反約束。
這確實是一個凌亂的邊緣情況,需要處理,這是適當的過程 受影響的重要性。如果發生這樣的錯誤,沒有乾淨,優雅,簡單,直接的出路,但希望以上是有用的信息。
在理論上忽略你對innodb和思考的具體問題,失敗可能發生在請求處理的任何一個步驟,因此不會建議依賴數據庫在發生故障時能夠做什麼。想象一下,當數據庫希望告訴你「是的,我做到了」時,你發送一個請求並且通信失敗(此外,假設你中間有一個**中介器**,並且中介器之間的通信失敗和客戶)。 – FDavidov