旁徵博引-詳解SQL四種標準的事務隔離級別
1 錯誤的讀現象
要了解事務隔離級別之前,讓我們來了解爲什麼需要對事務進行隔離,很簡單,就是因爲在多個事務併發,交錯執行過程中容易出現數據錯誤,爲了保障數據的一致和安全,我們就需要對事務進行隔離,那麼事務併發的過程會出現哪些錯誤呢?
在ANSI/ISO 標準SQL92中提到了三種不同出錯的讀現象(Read Phenomena),接下來我們來一一介紹:
- 髒讀 Read out of invalid data 髒讀又稱無效數據讀取,那麼爲什麼會讀取到無效的數據呢?
我們知道,在一個含有UPDATE語句更新數據的事務中,UPDATE語句更新了數據,但是由於某種原因事務回滾了,而在這個過程中,即在UPDATA語句更新數據後、事務回滾之前,該數據被另外一個事務讀取了,那麼這個數據就是一個無效的數據,該無效數據的讀出就稱之爲“髒讀”。
舉個栗子,在銀行存取的時候,假設某一賬戶的餘額爲1000,事務T1更新了賬戶餘額1200,另一事務T2讀取了該數據1200,結果另一邊的事務T1因爲某種原因回滾了操作,賬戶餘額又爲1000了,那麼這1200就被髒讀,這1200也可以稱爲髒數據。 - 不可重複讀 Unrepeatable reads 也稱之爲”Read-write conflict,它是一種與事務交錯執行相關的計算錯誤(is a computational anomaly associated with interleaved execution of transactions),是指對於一個事務範圍內的兩次相同的讀出操作,卻得到不相同的數據,爲什麼會造成這樣的結果呢?
假設給定一個schedule,它有兩個事務T1和T2
在上面的例子我們可以看到,在事務T1兩個讀操作R的間隔中,另外一個事務T2執行了讀操作並修改了數據,這樣就導致了事務T1讀到不同的數據。
注意區別髒讀和不可重複讀
髒讀是一個事務讀取到無效的數據,即在另一個事務數據更新後、未提交數據庫前讀取到的數據,那麼在數據更新前和提交數據庫後讀取的數據就不是髒數據了
不可重複讀讀取的就是另一個數據更新前和提交數據庫後的數據,那麼這些數據就不是髒數據了,雖然讀取的數據不是髒數據,但這些數據卻是不一致,這和髒讀一樣都是致命的問題。
- 幻讀 Phantom reads 幻讀是不可重複讀的一種特殊情況,它是指,在一個事務過程中,另外一個事務向正在被讀的記錄中添加或刪除一行。
在上面的例子中,事務T1兩次讀取操作的間隔中,新增加的數據,那麼就可能導致兩次讀取的數據不一致。
簡單區別一下不可重複讀和幻讀,幻讀是不可重複讀的一種特殊情況,它特殊之處在於,兩次得到的記錄數不同,可能多一行可能少一行。
2 隔離級別
那麼如何避免上述的情況呢?接下來我們來介紹SQL標準的四種事物隔離級別:
- 讀未提交 READ UNCOMMITTED
該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的數據。
該級別不能防止髒讀、不可重複讀和幻讀 - 讀已提交 READ COMMITTED
該隔離級別表示一個事務只能讀取另一個事務已經提交的數據。
該級別可以防止髒讀。
大多數情況下推薦值。 - 可重複讀 REPEATABLE READ
該隔離級別表示一個事務在整個過程中可以多次重複執行某個查詢,並且每次返回的記錄都相同。
該級別可以防止髒讀、不可重複讀。 - 串行操作 SERIALIZABLE
所有的事務依次執行,這樣事務之間就完全不可能干擾。
該級別可以防止髒讀、不可重複讀和幻讀。
嚴重影響程序性能,通常情況下不會使用該級別。
- Oracle默認的事務隔離級別是讀已提交
- MySQL默認的事務隔離級別是可重複讀
值得注意的是,MySQL在5.5.8版本後默認的存儲引擎是InnoDB,InnoDB存儲引擎默認的隔離級別當然也是可重複讀Repeatable Read,但InnoDB存儲引擎採用了Next-Key Lock的鎖算法,因此避免了幻讀的產生。
3 查看和設置事務隔離級別
接下來我們已MySQL爲例來查看和設置事務隔離級別
- 首先我們可以通過系統變量
transaction_isolation
或global.transaction_isolation
來查看當前會話或者全局的事務隔離級別,有兩種方式來查看系統變量:
方式一:SELECT @@transaction_isolation
方式二:SHOW VARIABLES LIKE 'transaction_isolation
2.設置事務隔離級別的語法
SET [ GLOBAL | SESSION ] TRANSACTION ISOLATION LEVEL
{
READ UNCOMMITTED
| READ COMMITTED
| REPEATABLE READ
| SERIALIZABLE
}
我們可以看到GLOBAL
和SESSION
是可選的
- 如果使用了
GLOBAL
關鍵字,那麼就表示設置的事務隔離級別面向全局會話的,注意的是,設置的全局會話事務隔離級別在當前會話不會生效,只會在接下來新的會話後才生效 - 如果使用了
SESSION
關鍵字,表示設置本次會話的事務隔離級別 - 如果都沒有使用,那麼就表示設置一次操作的事物隔離級別,在下一事務操作中使用該事務隔離級別,並且隨着該事務的提交而失效。
4 參考
百度百科-髒讀
百度百科-髒數據
wikipedia Read-write confilct
wikipedia Isolation(database systems)
CSDN博客-SQL標準中的事務四種隔離級別
百度經驗-MySQL如何查看和設置事務隔離級別