上一篇文章提到併發狀態的 transaction 仍然會遇到一些不預期的錯誤,分別有髒讀、不可重複讀、幻讀,今天就要來看看資料庫是怎麼解決這些問題的。
其實當你第一次思考這個問題的時候,你心中可能會想到一個解法
那不然…不要併發執行…序列化執行就沒事了…?
這個觀念是對的,它的確可以解決資料不一致的問題,然而這樣的一致性卻是用效能換來的,當你遇到高流量的狀況,這樣系統很可能會直接掛掉的,因此最好的方式是因應不同的情況,在 效能 與 一致性 間做一個權衡取捨,也就是這裡要介紹的隔離層級。
上圖就是今天要介紹的四種隔離層級,最上面的 read uncommitted 效能最好,但一致性最差,到了最下面的 serializable,變成一致性最好,但效能最差。
這是最低的隔離層級,SELECT 指令可以讀取其他 transaction 尚未 commit 的結果,如果這個尚未被 commit 的結果後來被 rollback 了,就會讀取到被取消的資料,也就是剛剛提過的「髒讀」。不過 UPDATE 等「寫」的操作是不會成功的。
這種隔離層級可能產生:
這個隔離層級只允許讀取其他 transaction commit 過的資料,因此可以解決髒讀的問題,不過如果一個 transaction 的兩個 SELECT 語法間有另一個交易 commit 了新資料,會造成第一次讀取與第二次讀取結果不一致的問題,也就是上面介紹過的不可重複讀。
這種隔離層級可能產生:
此種隔離層級為 innodb 預設的隔離層級,不會考慮別的 transaction 的修改,同一個 transaction 內,除非自己修改,否則多次 SELECT 的結果都會相同,解決了不可重複讀的問題。
這種隔離層級可能產生:
在一開始提過,是一個用效能換取一致性的隔離層級,讓所有 transaction 序列化執行,避免併發可能會造成的問題。
這篇文簡單介紹了併發的 transaction 可能會發生的三種問題與它的解法 —四種隔離層級,你可能會好奇隔離層級又是怎麼做到的?其實隔離層級背後運用了一個概念:鎖(Lock),如果對這部分有興趣的讀者再自行研究囉。