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多版本併發控制!它實現讀取資料不用加鎖,可以讓讀取資料同時修改。修改資料時同時可讀取。
、
、