事務隔離級別讀書筆記分享
-
在MVCC併發控制中,讀操作可以分成兩類:快照讀 (snapshot read)與當前讀 (current read)。快照讀,某一時刻的一致性讀,不用加鎖。當前讀,讀取的是記錄的最新版本,並且,當前讀返回的記錄,都會加上鎖,保證其他事務不會再併發修改這條記錄。
- MySQL在RR隔離級別下,快照讀和當前讀如果在一個會話中先後出現,可能會出現幻讀。因為快照讀不加鎖,會允許新的插入,當前讀需要讀到塊的最新版本,因此快照讀和當前讀兩次操作間,就可能會出現幻讀。 https://www.cnblogs.com/crazylqy/p/7612230.html
- MySQL為實現RR隔離級別,帶來了很大的代價,引入了Next-Key Locking解決當前讀模式下的幻讀問題。Next-Key Locking可能會導致大量的DML失敗。 https://www.cnblogs.com/crazylqy/p/7689447.html,Oracle沒有RR隔離級別,在read only級別下,Oracle沒有幻讀的問題(是快照讀的模式),在read committed級別下,快照讀、當前讀以及混合的【快照讀和當前讀】下都存在幻讀的問題。 https://www.cnblogs.com/crazylqy/p/7614092.html
- RR隔離級別,MySQL是依靠MVCC實現的可重複讀(read view),同時依靠MVCC實現快照讀下的幻讀問題,依靠Next-Key Locking實現當前讀下的幻讀問題,所以MySQL InnoDB的可重複讀並不保證避免幻讀,需要應用顯式的使用加鎖讀來保證,而這個加鎖讀使用到的機制就是next-key locks。
- 髒讀、不可重複讀、幻讀,是一種缺陷,越往後,解決缺陷的成本越高
- 隔離級別越高,能解決的“缺陷”越多,為什麼不直接使用最高的事務隔離級別,那不就沒有缺陷了? 因為隔離級別越高,併發性可能會越低。
- 髒讀,解決 寫不阻塞讀的問題,提高併發性,犧牲讀一致性。現在絕大多數的主流資料庫,都是透過MVCC來解決寫不阻塞讀的問題,不是透過經典的鎖來實現。
- 為什麼會出現不可重複讀取?
在經典的read commited方式下,對於讀取過的資料並不加鎖(讀取的當下加共享鎖,讀取完成後釋放共享鎖),那麼再次訪問時資料可能已經被其他事務修改。 - 如何才能做到可重複讀?
老一輩的資料庫藝術家用的方式是加鎖,對讀取過的資料加鎖,就能保證每一次讀取到的資料都是一樣的,因為對讀取過的資料加鎖後,資料無法發生修改了。這也是repeatable read這個隔離級別要解決的問題,但是經典的實現可重複讀的方式會產生幻讀。現在絕大多數的主流資料庫,是透過MVCC來做到的可重複讀,不是透過加鎖。 - 經典的可重複讀提供了一個一致性(語句級和事務級)的讀取方式,雖存在幻讀,單從一致性的角度看,並不是一個大的缺陷,如果以經典的鎖的方式去實現可重複讀,發生死鎖的機率極大,但帶來的一個(好的)副作用,解決了丟失更新的問題。
- 按照經典的隔離級別定義,read uncommited,read commited,都不能提供一致性讀。因為當下主流資料庫都基於MVCC實現,不基於經典的鎖方式,所以都實現了在read commited級別下的語句級的一致性。經典的隔離級別下,repeatable read在語句級一致性的基礎上還做到了事務級的一致性。
- 針對oracle的隔離級別來說,read commited級別能夠提供語句級的一致性,這個隔離級別避免不了事務級的幻讀的問題,需要read only或者最高的SERIALIZABLE級別。
- 在一個採用共享讀鎖(而不是多版本)的資料庫中,如果啟用了REPEATABLE READ,可以避免丟失更新的問題。原因是:已被讀取的資料會在上面加一個鎖(共享讀鎖,非排它鎖),這個鎖會保證資料不能被任何其他事務修改。
- 在可重複讀(REPEATABLE READ,簡稱RR)隔離級別下,read view是在第一個讀請求發起時建立的。在讀已提交(READ COMMITTED,簡稱RC)隔離級別下,則是在每次讀請求時都會重新建立一份read view。根據上面提到的說法,RC隔離級別下,是每次發起SELECT都會建立read view,也就是每次SELECT都能讀取到本次查詢開始時的已經commit的資料,所以才會出現不可重複讀、幻讀現象。
- read view 判斷當前版本資料項是否可見
在innodb中,建立一個新事務的時候,innodb會將當前系統中的活躍事務列表(trx_sys->trx_list)建立一個副本(read view),副本中儲存的是系統當前不應該被本事務看到的其他事務id列表。當使用者在這個事務中要讀取該行記錄的時候,innodb會將該行當前的版本號與該read view進行比較。
具體的演算法如下:
- 設該行的當前事務id為trx_id_0,read view中最早的事務id為trx_id_1, 最遲的事務id為trx_id_2.
- 如果trx_id_0< trx_id_1的話,那麼表明該行記錄所在的事務已經在本次新事務建立之前就提交了,所以該行記錄的當前值是可見的。跳到步驟6.
- 如果trx_id_0>trx_id_2的話,那麼表明該行記錄所在的事務在本次新事務建立之後才開啟,所以該行記錄的當前值不可見.跳到步驟5。
- 如果trx_id_1<=trx_id_0<=trx_id_2, 那麼表明該行記錄所在事務在本次新事務建立的時候處於活動狀態,從trx_id_1到trx_id_2進行遍歷,如果trx_id_0等於他們之中的某個事務id的話,那麼不可見。跳到步驟5.
- 從該行記錄的DB_ROLL_PTR指標所指向的回滾段中取出最新的undo-log的版本號,將它賦值該trx_id_0,然後跳到步驟2.
- 將該可見行的值返回。
需要注意的是,新建事務(當前事務)與正在記憶體中commit 的事務不在活躍事務連結串列中。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22034023/viewspace-2153328/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL 事務隔離級別MySql
- PostgreSQL事務隔離級別SQL
- 事務、特性、隔離級別
- MySQL事務隔離級別MySql
- [Mysql]事務/隔離級別MySql
- MySQL事務的隔離級別MySql
- MySQL的事務隔離級別MySql
- 理解MySQL事務隔離級別MySql
- mysql修改事務隔離級別MySql
- Oracle-事務隔離級別Oracle
- JDBC 事務(一) 隔離級別JDBC
- SqlServer事務詳解(事務隔離性和隔離級別詳解)SQLServer
- MySQL事務隔離級別和MVCCMySqlMVC
- 事務系統的隔離級別
- mysql如何修改事務隔離級別MySql
- mysql事務隔離級別和鎖MySql
- 啥是 MySQL 事務隔離級別?MySql
- Mysql 四種事務隔離級別MySql
- Mysql鎖與事務隔離級別MySql
- 理解mysql的事務隔離級別MySql
- 資料庫事務隔離級別資料庫
- MySQL事務隔離級別詳解MySql
- SQL Server事務的隔離級別SQLServer
- 資料庫學習筆記:事務的特性和隔離級別資料庫筆記
- 資料庫事務與事務的隔離級別資料庫
- 事務隔離級別(圖文詳解)
- 事務ACID特性與隔離級別
- 資料庫事務與隔離級別資料庫
- 事務基礎特性及隔離級別
- MySQL 的四種事務隔離級別MySql
- 面試被吊打系列 - 事務隔離級別面試
- MySQL 事務的隔離級別初窺MySql
- CYmysql事務隔離級別詳情dbzMySql
- 資料庫事務及其隔離級別資料庫
- MySQL的四種事務隔離級別MySql
- 檢視ORACLE事務隔離級別方法Oracle
- SQL Server 事務隔離級別詳解SQLServer
- ORACLE資料庫事務隔離級別Oracle資料庫