一、為什么MySQL在innodb引擎中即使使用了MVCC機制仍然會出現丟失更新
mvcc在innodb中只負責解決讀寫沖突,把普通select語句變成快照讀。寫沖突仍然是靠鎖來解決的。因此要解決你說的丟失更新,要用select…for update主動加x鎖。
當然mvcc不是說完全不能解決丟失更新,比如postgresql的serializable隔離級別下,遇到寫寫沖突直接向客戶端返回異常,保證只有一個事務可以更新成功。
Mysql在可重復讀隔離級別下可保證事務較高的隔離性,同樣的sql查詢語句在一個事務里多次執行查詢結果相同,就算其它事務對數據有修改也不會影響當前事務sql語句的查詢結果
?? 這個隔離性就是靠MVCC(Multi-Version Concurrency Control)機制保證
對一行數據的讀和寫兩個操作默認是不會通過加鎖互斥來保證隔離性,避免了頻繁加鎖互斥而在串行化隔離級別為了保證較高的隔離性是通過將所有操作加鎖互斥來實現的延伸閱讀:
二、MVCC多版本并發控制機制的實現
undo日志版本鏈是指一行數據被多個事務依次修改過后,在每個事務修改完后,Mysql會保留修改前的數據undo回滾日志,并且用兩個隱藏字段trx_id和roll_pointer把這些undo日志串聯起來形成一個歷史記錄版本鏈。
在可重復讀隔離級別,當事務開啟,執行任何查詢sql時會生成當前事務的一致性視圖read-view該視圖在事務結束之前都不會變化(如果是讀已提交隔離級別在每次執行查詢sql時都會重新生成)該視圖由執行查詢時所有未提交事務id數組(數組里最小的id為min_id)和已創建的最大事務id(max_id)組成事務里任何sql的查詢結果需要從對應版本鏈里的最新數據開始逐條跟read-view做比對從而得到最終的快照結果1.如果 row 的 trx_id 落在綠色部分( trx_id 2. 如果 row 的 trx_id 落在紅色部分( trx_id>max_id ),表示這個版本是由將來啟動的事務生成的,是不可見的(若 row 的 trx_id 就是當前自己的事務是可見的); 3. 如果 row 的 trx_id 落在黃色部分(min_id <=trx_id<= max_id),那就包括兩種情況: 若 row 的 trx_id 在視圖數組中,表示這個版本是由還沒提交的事務生成的,不可見(若 row 的 trx_id 就是當前自己的事務,是可見的); 若 row 的 trx_id 不在視圖數組中,表示這個版本是已經提交了的事務生成的,可見。