事务隔离机制原理分析以及是否可以防止订单超卖
事務的隔離機制是指:
Read Uncommitted(讀取未提交內容)
Read Committed(讀取提交內容)
Repeatable Read(可重讀)
Serializable(可串行化)
具體的解釋最經典的MySQL書《高性能MySQL(第3版)》已經有了就不在其他地方再引用了:
隔離機制的比較
其實也有人喜歡用鎖來控制并發,書中還提到了“隱式”和“顯示鎖定”,是這么建議的:
雖然這樣,但是其實如果不經過實際的演練還是很難理解上面說的事務隔離機制到底怎么樣可以防止并發。
1.查看MySQL版本
我們的版本是5.1.7
2.查看存儲引擎
>show engines;
存儲引擎是:InnoDB
3.實驗表
假設有個商品表g,關鍵字段num表示庫存,name表示商品名稱
主要就是看不同事務隔離機制下并發修改庫存是否會出現超賣。
假設我們的程序需要先查詢庫存,如果庫存>0都可以賣,update扣庫存,否則rollback。
為了制造并發肯定需要2個事務,假設是A和B。
4.確認事務隔離機制
修改會話的事務隔離級別
set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;
>select @@global.tx_isolation,@@tx_isolation;
5.Serializable
場景一:
顯然一開始AB查詢的數據是一樣的num=1
A開始update
這時候在等待,無法update。
過一會就超時了。
如果這個時候B也update那么一樣會等待超時
所以這樣,AB就會都超時。
這時即使commit也是返回0,數據庫不會變化。
場景二:
A在update等待的時候,B馬上commit,但是B沒有update
查看結果
這次A成功的扣庫存。
所以從上面可以得出一個結論:serializable是可以很好的控制并發。
然后需要把庫存改為1,便于測試。
6.read committed
>set session transaction isolation level read committed;
>select @@global.tx_isolation,@@tx_isolation;
場景三:
初始化AB查出來的庫存都是1,然后A可以update一條數據,無等待。
這時候AB再比較下庫存,A已經是0,B是1,因為A沒有commit。
然后A執行commit操作,這時候B再查已經是庫存0;
這時候B執行update返回是0行,因為update不能滿足where條件,所以B只有Commit,然后重新提交。
場景四:
一開始AB都是一樣的庫存1,然后A開始update,然后A的庫存是0,B是1,因為A還沒有提交。
這時候B再update
按照前面的經驗,B等待其實是再等A提交,A如果一直不提交,B就會超時。
這時A提交commit,B查詢就得到A更新后的結果,這時B查到庫存是0自然不會去更新,也就只能結束事務。
場景五:
AB先后update,然后A在B超時之前commit,這時由于B已經讀到A更新后的結果0,所以B就不能成功update。
7.repeatable read
>set session transaction isolation level repeatable read;
>select @@global.tx_isolation,@@tx_isolation;
場景六:
然后A開始update,然后A和B分別讀到庫存是1和0
然后A提交commit,這時候再查看A和B的庫存還是保持不變。
這時候B再次嘗試update
依然是返回0條,說明更新不成功。
場景八:
AB同時update
如果A不及時commit那么B肯定會超時
場景九:
就是場景八A及時commit
如果A及時commit
所以可以看出無論是read committed還是repeatable read只要update的條件where ?num>0足夠充分都是可以控制并發防止超賣的。
如果沒有帶where ?num>0這個控制條件,那么肯定會可以update成功的。
8.read uncommitted
這個是需要杜絕的,就不討論了。
9.如果沒有帶where ?num>0,那么會怎么樣呢。其實只要理解了上述流程就可以想明白會怎么樣。
對于read committed
A已經update,B讀到庫存是0自然不會去更新;
A沒有update,B讀到庫存是1,這要看A會不會及時提交;
如果A及時提交,B自然會去更新因為滿足where條件,且成功,這樣就超賣-1;
這時候由于B沒有提交,所以AB分別查出0和-1
然后B提交commit,AB查出的都是-1,就不演示了。
修改會話為repeatable read
AB先后update,B在等待
然后A立即提交commit,B馬上update得到返回。
結果就是-1產生了超賣:
總結:
1.使用serializable是可以防止超賣,但是性能怎么樣需要數據說明;
2.read committed和repeatable read帶上where條件庫存num>0都是可以防止超賣的,不過需要處理超時。
3.其他各種組合情況還會更復雜,具體具體問題具體分析。
總結
以上是生活随笔為你收集整理的事务隔离机制原理分析以及是否可以防止订单超卖的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring源码分析【8】-分布式环境S
- 下一篇: JVM内存溢出的几种情形