1. 程式人生 > 其它 >Mysql 一致性

Mysql 一致性

關係型資料庫的一致性

3種讀

髒讀

一個事務讀取到另一個事務未提交的資料

不可重複讀

不可重複讀的重點是修改;同樣的條件,

第1次和第2次讀取id相同的記錄,值卻不一樣。

幻讀

幻讀的重點在於新增或者刪除;同樣的條件, 第1次和第2次查出的記錄數不一樣

不可重複讀解決

  • 對於前者, 只需要鎖住滿足條件的記錄

    select * from user where userid=111 LOCK IN SHARE MODE; ;

  • 對於幻讀, 鎖住條件依然無效

    比如select * from user where enable=1 for update

    此時別的事務 新增 了一條enable=1的記錄

    再次執行select ...for update時,幻讀還存在

  • 快照讀(普通的select 無幻讀問題)

幻讀解決方案

https://blog.csdn.net/nandao158/article/details/116007366

4種隔離級別

以上三種問題,將隔離級別劃分為四種。

  • read uncommited 未提交讀
  • 會有髒讀
  • read commited 已提交讀
    • 無髒讀問題 (oracle預設隔離級別)
  • repeatable read 可重複讀
    • 無不可重複讀問題。 (mysql 預設隔離級別)
  • serializable 序列化
    • 無幻讀問題 。SERIALIZABLE會在讀取的每一行資料上加鎖

共享鎖和排它鎖

MySQL資料庫的鎖,按照作用範圍劃分為: 行級鎖、頁級鎖和表級鎖

行級鎖又分為共享鎖和排他鎖兩種

共享鎖、讀鎖

select ...lock in share mode 其他事務可讀不可改。

排它鎖、寫鎖、獨佔鎖

select ...for update 其他事務不可讀

insert /delete/update

使用場景

訂單的商品數量
    如果是同一張表的應用場景,舉個例子,電商系統中計算一種商品的剩餘數量,在產生訂單之前需要確認商品數量>=1,產生訂單之後應該將商品數量減1。
    1 select amount from product where product_id=1;
    2 update product set amount=amount-1 where product_id=1 ;

如果1查詢出amount為1,但是這時正好其他session也買了該商品併產生了訂單,那麼amount就變成了0,那麼這時第二步再執行就有問題。

那麼採用lock in share mode可行嗎,也是不合理的,因為兩個session同時鎖定該行記錄時,這時兩個session再update時必然會產生死鎖導致事務回滾。

總結

lock in share mode適用於兩張表存在業務關係時的一致性要求,for update適用於操作同一張表時的一致性要求。

MVCC

(Multiversion Concurrency Control)多版本併發控制

如何解決加鎖後的效能問題的?

答案就是,MVCC多版本併發控制!它實現讀取資料不用加鎖,可以讓讀取資料同時修改。修改資料時同時可讀取。

覆蓋索引、回表

https://zhuanlan.zhihu.com/p/339666157