如果資料庫中的事務都是序列執行的,這種方式可以保障事務的執行不會出現異常和錯誤,但帶來的問題是序列執行會帶來效能瓶頸;
而事務併發執行,如果不加以控制則會引發諸多問題,包括死鎖、更新丟失等等。
這就需要我們在效能和安全之間做出合理的權衡,使用適當的併發控制機制保隨併發事務的執行。
首先我們先來了解一下併發事務會帶來哪些問題。併發事務訪問相同記錄大致可歸納為以下3種情況:
因為讀取記錄並不會對記錄造成任何影響,所以同個事務併發讀取同一記錄也就不存在任何安全問題,所以允許這種操作。
如果允許併發事務都讀取同一記錄,並相繼基於舊估對這一記錄做出修改,那麼就會出現前乙個事務所做的修改被後面事務的修改覆蓋,即出現提交覆蓋的問題。
另外一種情況,併發事務相繼對同一記錄做出修改,其中乙個事務提交之後之後另乙個事務發生回滾,這樣就會出現已提交的修改因為回滾而丟失的問題,即回滾覆蓋問題。
這兩種問題都造成丟失更新,其中回滾覆蓋稱為第一類丟失更新問題,提交覆蓋稱為第二類丟失更新問題。
這種情況較為複雜,也最容易出現問題。
如果乙個事務讀取了另乙個事務尚未提交的修政記錄,那麼就出現了髒讀的問題;
如果我們加以控制使得乙個事務只能讀取其他已提交務的修改的資料,那麼這個事務在另一手物提交修改前後讀取到的資料是不一樣的,這就意味看發生了不可重複讀;
如果乙個事務根據一些條件查詢到一些記錄,之後另一事物向表中插入了一些記錄,原先的事務以相同條件再次查詢時發現得到的結果跟第一次查詞得到的結果不一致,這就意味著發生了幻讀。
精煉解釋:
當然, 從總的結果來看, 似乎兩者都表現為兩次讀取的結果不一致.
但如果你從控制的角度來看, 兩者的區別就比較大
對於前者, 只需要鎖住滿足條件的記錄
對於後者, 要鎖住滿足條件及其相近的記錄
詳細說明:
不可重複讀
是指在乙個事務內,多次讀同一資料。在這個事務還沒有結束時,另外乙個事務也訪問該同一資料。那麼,在第乙個事務中的兩次讀資料之間,由於第二個事務的修改,那麼第乙個事務兩次讀到的的資料可能是不一樣的。這樣就發生了在乙個事務內兩次讀到的資料是不一樣的,因此稱為是不可重複讀。
例如,乙個編輯人員兩次讀取同一文件,但在兩次讀取之間,作者重寫了該文件。當編輯人員第二次讀取文件時,文件已更改。原始讀取不可重複。如果只有在作者全部完成編寫後編輯人員才可以讀取文件,則可以避免該問題
要避免這種情況,通常可以用 set tran isolation level repeatable read 來設定隔離級別,這樣事務a 在兩次讀取表t中的資料時,事務b如果企圖更改表t中的資料(細節到事務a讀取資料)時,就會被阻塞,知道事務a提交! 這樣就保證了,事務a兩次讀取的資料的一致性。
例如,乙個編輯人員更改作者提交的文件,但當生產部門將其更改內容合併到該文件的主複本時,發現作者已將未編輯的新材料新增到該文件中。如果在編輯人員和生產部門完成對原始文件的處理之前,任何人都不能將新材料新增到文件中,則可以避免該問題。
對於以上提到的併發事務執行過程中可能出現的問題,其嚴重性也是不一樣的,我們可以按照問題的嚴重程度排個序:
丟失更新 > 髒讀 > 不可重複讀 > 幻讀因此如果我們可以容忍一些嚴重程度較輕的問題,我們就能獲取一些效能上的提公升。於是便有了事務的四種隔離級別:
sql規範定義了以上四種隔離級別,但是並沒有給出如何實現四種隔商級別,因此不同資料庫的實現方式和使用方式也並不相同。
而sql隔離級別的標準是依據基於鎖的實現方式來制定的,因為有必要先了解一下傳統的基於鎖的隔離級別是如何實現的。
既然說到傳統的隔離級別是基於鎖實現的,我們先來了解一下鎖。
需要注意的是,加了共享鎖的記錄,其他事務也可以獲得該記錄的共享鎖,但是無法獲取該記錄的排他鎖,即s鎖和s鎖是相容的,s鎖和x鎖是不相容的;
而加了排他鎖的記錄,其他事務既無法獲取該記錄的共享鎖也無法獲取排他鎖,即x鎖和x鎖也是不相容的。
另外,剛剛說到事務對一條記錄進行讀操作時,需要先獲取該記錄的s鎖,但有時務在讀取記錄時需要阻止其他事務訪問該記錄,這時就需要獲取該記錄的x鎖。
以mysql為例,有以下兩種鎖定讀的方式:
select…lock in share mode;如果事務執行了該語句,則會在讀取的記錄上加s鎖,這樣就允許其他事務也能獲取到該記錄的s鎖:而如果其他事務需要獲取該記錄的x鎖,那麼就需要等待當前事務提交後釋放掉s鎖。
select……for update;如果事務執行了該語句,則會在讀取的記錄上加x鎖,這樣其他事務想要取該記錄的s鎖或x鎖,那麼需要等待當前事務提交後釋放掉x鎖。
對於鎖的粒度而言鎖又可以分為兩種:
在基於鎖的實現方式下,四種隔離級別的區別就在於加鎖方式的區別:
注意:
例如,在讀已提交隔離級別下,讀操作所加s鎖為短鎖,寫操作所加x鎖為長鎖。
對於可重複讀和序列化隔離級別,讀操作所加s鎖和寫操作所加x鎖均為長鎖,即事務獲取鎖之後直到事務提交後才能釋放,這種把獲取鎖和釋放鎖分為兩個不同的階段的協議稱為兩階段鎖協議
(2-phase locking)。
兩階段鎖協議規定:
兩階段鎖協議能夠保證事務序列化執行,解決事務併發問題,但也會導致死鎖發生的概率大大提公升。
不同資料庫對於sql標準中規定的隔離級別支援是不一樣的,資料庫引擎實現隔離級別的方式雖然都在盡可能地貼近標準的隔離級別規範,但和標準的預期還是有些不一樣的地方。
mysql(innodb)支援的4種隔離級別,與標準的各級隔離級別允許出現的問題有些出入,比如mysql在可重複讀隔離級別下可以防止幻讀的問題出現,但也會出現提交覆蓋的問題。
相對於傳統隔離級別基於鎖的實現方式,mysql 是通過mvcc(多版本併發控制)來實現讀-寫併發控制
,又是通過兩階段鎖來實現寫-寫併發控制
的。即 mvcc+2pl 實現
mvcc是一種無鎖方案,用以解決事務讀-寫併發的問題,能夠極大提公升讀-寫併發操作的效能。
Mysql基礎篇 24 MVCC理解
mvcc multi version concurrent control mvcc即多個不同版本的資料實現併發控制技術,其基本思想是為每次事務生成乙個新版本的資料,再讀取資料時選擇不同版本的資料即可以實現事務結果的完整性讀取。即通過儲存資料在某個時間點的快照來實現,不同儲存引擎的mvcc實現不一致...
mysql與zk mysql基礎篇
登入 本機 mysql uroot p 輸入密碼 顯示資料庫 show databases 使用庫use 資料庫名 顯示資料庫中的表 show tables 顯示表結構 desc 表名 show create table 表名 檢視表結構 查詢字段資料 select from 表名 建立庫 crea...
MVCC與MySQL各大引擎介紹
多版本併發控制是mysql的innodb採用的併發控制方案,在可重複讀下預設使用該併發控制方案 原理 總結 通過多條記錄,多版本,只做增量的方式來保證可重複讀和併發控制 版本校驗 索引和資料分開在兩個檔案,因此支援行鎖效能不好保障,所以沒有設計支援行鎖和事務 崩潰後資料恢復困難 但是myisam的儲...