MySQL InnoDB 事務是否可序列化?
我對 MySQL 事務是否可序列化以及是否防止讀取異常感到困惑?
例如,如果我
SELECT
從一行中獲取一個值,那麼UPDATE
該行通過遞增該值來實現。有可能對UPDATE
正在讀取的行進行另一個查詢,從而導致不正確的更新。但是,我的印像是,即使我將這兩個語句包裝在一個事務中,也不能保證我不會遇到競爭條件。請參閱此 StackOverflow 執行緒。因此,為了防止這種情況,我使用
UPDATE
了COALESCE
單個查詢,因此保證是原子的。這個假設正確嗎?或者交易是否會在這裡起作用以保證沒有競爭條件?我從有關隔離級別的 MySQL 5.7 文件中看到事務預設情況下是,
REPEATABLE_READ
而不是SERIALIZABLE
. 如果我將事務級別設置為SERIALIZABLE
怎麼辦?我試圖閱讀文件,REPEATABLE_READ
但它並沒有增加我對這個問題的理解。
根據MySQL 文件,SERIALIZABLE 是:
此級別類似於 REPEATABLE READ,但如果禁用自動送出,InnoDB 會將所有普通 SELECT 語句隱式轉換為 SELECT … FOR SHARE。如果啟用了自動送出,則 SELECT 是它自己的事務。因此,它是只讀的,並且如果作為一致(非鎖定)讀取執行並且不需要阻塞其他事務,則可以序列化。(如果其他事務修改了選定的行,要強制一個普通的 SELECT 阻塞,禁用自動送出。)
鎖定 FOR SHARE 行不等同於 SERIALIZABLE 事務,因為它不能防止由 SELECT 語句返回的競速事務插入行。
SERIALIZABLE 上的 PostgreSQL 文件提供了一個發生這種情況的範例。在您的特定情況下,我相信 MySQL 的 SERIALIZED 隔離級別不會保護您,因為兩個競爭事務都可以鎖定該行 FOR SHARE,然後都可以發出 UPDATE 增加值,一個事務將通過,下一個事務將等待第一個送出,然後通過。您將得到一個增量而不是兩個的淨值。
- 盡量減少您在交易中的投入——以保持快速。
- 始終檢查錯誤並重新啟動事務。
底線:競爭條件很少見,您將處理那些確實發生的情況。
至於
SERIALIZABLE
——那是最慢的模式;不要用它來提高速度。無論如何,您是否期望每秒有數千筆交易?