- 1 mvcc是什么?
阿里數據庫內核2017/12月報
多版本控制: 指的是一種提高并發的技術。最早的數據庫系統,只有讀讀之間可以并發,讀寫,寫讀,寫寫都要阻塞。引入多版本之后,只有寫寫之間相互阻塞,其他三種操作都可以并行,這樣大幅度提高了InnoDB的并發度。在內部實現中,與Postgres在數據行上實現多版本不同,InnoDB是在undolog中實現的,通過undolog可以找回數據的歷史版本。找回的數據歷史版本可以提供給用戶讀(按照隔離級別的定義,有些讀請求只能看到比較老的數據版本),也可以在回滾的時候覆蓋數據頁上的數據。在InnoDB內部中,會記錄一個全局的活躍讀寫事務數組,其主要用來判斷事務的可見性。
MVCC是一種多版本并發控制機制。
mvcc小結如下:
* MVCC是被Mysql中 `事務型存儲引擎InnoDB` 所支持的;
* **應對高并發事務, MVCC比`單純的加鎖`更高效**;
* MVCC只在 `READ COMMITTED` 和 `REPEATABLE READ` 兩個隔離級別下工作;
* MVCC可以使用 `樂觀(optimistic)鎖` 和 `悲觀(pessimistic)鎖`來實現;
* 各數據庫中MVCC實現并不統一
* 但是書中提到 "InnoDB的MVCC是通過在每行記錄后面保存**兩個隱藏的列**來實現的"(網上也有很多此類觀點), 但其實并不準確, 可以參考[MySQL官方文檔](https://dev.mysql.com/doc/refman/5.7/en/innodb-multi-versioning.html), 可以看到, InnoDB存儲引擎在數據庫每行數據的后面添加了**三個字段**, 不是兩個!!
- 2 MVCC是為了解決什么問題?
大家都應該知道,鎖機制可以控制并發操作,但是其系統開銷較大,而MVCC可以在大多數情況下代替行級鎖,使用MVCC,能降低其系統開銷. - 3 MVCC實現
MVCC是通過保存數據在某個時間點的快照來實現的. 不同存儲引擎的MVCC. 不同存儲引擎的MVCC實現是不同的,典型的有樂觀并發控制和悲觀并發控制. - 4 MVCC 具體實現分析
下面,我們通過InnoDB的MVCC實現來分析MVCC使怎樣進行并發控制的.
InnoDB的MVCC,是通過在每行記錄后面保存兩個隱藏的列來實現的,這兩個列,分別保存了這個行的創建時間,一個保存的是行的刪除時間。這里存儲的并不是實際的時間值,而是系統版本號(可以理解為事務的ID),沒開始一個新的事務,系統版本號就會自動遞增,事務開始時刻的系統版本號會作為事務的ID.下面看一下在REPEATABLE READ隔離級別下,MVCC具體是如何操作的.
而InnoDB實現MVCC的方式是:
事務以排他鎖的形式修改原始數據
把修改前的數據存放于undo log,通過回滾指針與主數據關聯
修改成功(commit)啥都不做,失敗則恢復undo log中的數據(rollback)
樂觀鎖和悲觀鎖
1 悲觀鎖
1、排它鎖,當事務在操作數據時把這部分數據進行鎖定,直到操作完畢后再解鎖,其他事務操作才可操作該部分數據。這將防止其他進程讀取或修改表中的數據。
2、實現:大多數情況下依靠數據庫的鎖機制實現
實現方式:
一般使用 select ...for update 對所選擇的數據進行加鎖處理,例如select * from account where name=”Max” for update, 這條sql 語句鎖定了account 表中所有符合檢索條件(name=”Max”)的記錄。本次事務提交之前(事務提交時會釋放事務過程中的鎖),外界無法修改這些記錄。
2 樂觀鎖
實現方式:
1、如果有人在你之前更新了,你的更新應當是被拒絕的,可以讓用戶重新操作。
2、實現:大多數基于數據版本(Version)記錄機制實現
具體可通過給表加一個版本號或時間戳字段實現,當讀取數據時,將version字段的值一同讀出,數據每更新一次,對此version值加一。當我們提交更新的時候,判斷當前版本信息與第一次取出來的版本值大小,如果數據庫表當前版本號與第一次取出來的version值相等,則予以更新,否則認為是過期數據,拒絕更新,讓用戶重新操作。
這樣看起來項目中ideainfo表用的version字段就是通過代碼級別實現的樂觀鎖的控制。
參考:
1 輕松理解MYSQL MVCC實現機制
2 MySQL-InnoDB-MVCC多版本并發控制
3 MySQL悲觀鎖&&樂觀鎖(并發控制)