事務隔離級別:可重復讀


MySQL [pom_5]> select @@global.tx_isolation;

+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ       |
+-----------------------+

如果事務隔離級別顯示REPEATABLE-READ,即是可重復讀。

事務的四種隔離級別

(引自: Innodb中的事務隔離級別和鎖的關系)

在數據庫操作中,為了有效保證並發讀取數據的正確性,提出的事務隔離級別。我們的數據庫鎖,也是為了構建這些隔離級別存在的。

隔離級別 臟讀(Dirty Read) 不可重復讀(NonRepeatable Read) 幻讀(Phantom Read)
未提交讀(Read uncommitted) 可能 可能 可能
已提交讀(Read committed) 不可能 可能 可能
可重復讀(Repeatable read) 不可 不可 可能
可串行化(Serializable ) 不可能 不可能 不可能

未提交讀(Read Uncommitted):允許臟讀,也就是可能讀取到其他會話中未提交事務修改的數據

提交讀(Read Committed):只能讀取到已經提交的數據。Oracle等多數數據庫默認都是該級別 (不重復讀)

可重復讀(Repeated Read):可重復讀。在同一個事務內的查詢都是事務開始時刻一致的,InnoDB默認級別。在SQL標准中,該隔離級別消除了不可重復讀,但是還存在幻象讀

串行讀(Serializable):完全串行化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞

可重復讀和幻讀

在可重復讀中,該sql第一次讀取到數據后,就將這些數據加鎖(悲觀鎖),其它事務無法修改這些數據,就可以實現可重復讀了。但這種方法卻無法鎖住insert的數據,所以當事務A先前讀取了數據,或者修改了全部數據,事務B還是可以insert數據提交,這時事務A就會發現莫名其妙多了一條之前沒有的數據,這就是幻讀,不能通過行鎖來避免。需要Serializable隔離級別 ,讀用讀鎖,寫用寫鎖,讀鎖和寫鎖互斥,這么做可以有效的避免幻讀、不可重復讀、臟讀等問題,但會極大的降低數據庫的並發能力。

但是MySQL、ORACLE、PostgreSQL等成熟的數據庫,出於性能考慮,都是使用了以樂觀鎖為理論基礎的MVCC(多版本並發控制)來實現。

實際測試結果

對相同db實例創建兩個連接:a和b,來測試select, select for update, update語句的生效情況

不使用select for update行級鎖

a先提交 b先提交
a先開啟事務 b的update內容 a的update內容
a先開啟事務 b的update內容 a的update內容

結果是誰最后提交,誰的結果生效

a先使用select for update, update行級鎖

a使用select for update a使用select for update a使用update
a開啟事務,b不開啟 b里面的select for update和update被阻塞 b不受影響 b里面的select for update和update被阻塞
a不開啟事務,b開啟 b不受影響 b不受影響 b不受影響
a,b開啟事務 b里面的select for update和update被阻塞 b不受影響 b里面的select for update和update被阻塞
a,b不開啟事務 b不受影響 b不受影響 b不受影響

結果是只有使用begin顯式開啟事務時,使用select for update才會對數據加上行級鎖,對其他連接的的select for update(對select沒有影響)和update造成阻塞效果。

a上鎖后修改提交,b讀取到的內容

下面是a開啟事務,然后使用a使用select for update,接着b使用select for update/select,a執行updat,最后commit,觀察整個過程中b的查詢效果。

b使用select for update b使用select
b開啟事務 b里面的select for update被阻塞,a提交后,b讀到的是a修改的內容 b不受a阻塞,讀到的仍是b事務開啟時的內容
b不開啟事務 b里面的select for update被阻塞,a提交后,b讀到的是a修改的內容 b不受a阻塞,讀到的數據在a提交后變化

在連接a使用begin開啟事務之后,select for update和update對連接b的阻塞效果

a先執行select for update a先執行update
b后執行select 未阻塞 未阻塞
b后執行select for update 阻塞 阻塞
b后執行update 阻塞 阻塞


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM