InnoDB 和隔離級別 - 可重複讀取不是一件壞事嗎?
我正在閱讀有關
InnoDB's
隔離級別的內容,這在很大程度上是有道理的,但我不明白為什麼是unrepeatable reads
一件壞事?不應該反過來嗎?舉些例子:
假設我們有一個用於銷售產品的庫存列,每次有人購買一件商品時,我們都會從該列中取出一件商品,使用
Repeatable read
或serializable
隔離級別不會破壞數據完整性嗎?例如:
TX A: start transaction; TX B: set session transaction isolation level repeatable read; TX B: start transaction; TX A: select stock from products; -- val = 8 TX B: select stock from products; -- val = 8 TX A: update products set stock = stock - 1; -- val = 7 TX B: select stock from products; -- val = 8 TX A: commit TX B: select stock from products; -- val = 8, incorrect! TX B: commit; TX B: select stock from products; -- val = 7
除非它在執行更新時使用正確的值?
InnoDB 隔離級別不是“壞”或“好”,這取決於您的應用程序在隔離方面需要什麼。
在您的範例中,通過使用可重複讀取,您可以確保一旦完成第一次選擇,從該事務的角度來看,沒有其他事務可以修改數據庫的狀態。換句話說,就好像您
START TRANSACTION WITH CONSISTENT SNAPSHOT
在第 5 行之前執行了“”。在某些情況下可能需要這樣做,讓我舉個例子:TX A: START TRANSACTION; TX A: SELECT * FROM products WHERE stock BETWEEN 4 AND 6; -- I see rows 4 and 6 only, -- and I want to update those only TX B: START TRANSACTION; TX B: INSERT INTO products (stock) VALUES (5); TX A: UPDATE products SET stock = 3 WHERE stock BETWEEN 4 AND 6; TX A: COMMIT; -- race condition TX B: COMMIT;
通過設置 InnoDB’s
REPEATABLE READ
,幻讀消失,因為 TX B 將在插入時被鎖定,直到 A 送出。但是,如果我們這樣做READ COMMITTED
,我們將獲得不同的輸出,這取決於 A 還是 B 先送出,這違反了 ACID 屬性,並且我們的應用程序可能不會期望。特別是,
STATEMENT
基於 - 的複制不需要幻讀,這就是為什麼READ COMMITTED
它是預設級別,甚至比READ COMMITTED
其他數據庫(需要可序列化才能獲得 InnoDB 行為)具有更嚴格的行為。如果第一個選擇是更新,則獨立執行這些事務將導致不同的結果(漂移從屬)。請注意,事務是以原子方式和串列方式寫入二進制日誌的。我同意您的觀點,大多數應用程序可能不需要這樣做,因為您將在應用程序級別處理這些情況。如果是這種情況,請使用
ROW
基於複製並將預設事務隔離級別設置為READ COMMITTED
. 在大多數情況下,您還將獲得更好的並發性。