MYSQL高併發與鎖機制

MySQL經常使用存儲引擎的鎖機制

MyISAM和MEMORY採用表級鎖(table-level locking)mysql

BDB採用頁面鎖(page-level locking)或表級鎖,默認爲頁面鎖sql

InnoDB支持行級鎖(row-level locking)和表級鎖,默認爲行級鎖數據庫

 

innodb和mysam

目前你們用的mysql中表的engine都是innodb,不多會用mysam了,就是由於在更新數據的時候mysam會鎖表,致使併發更新的時候只能一個個排隊更新,對效率影響很大,而innodb則是行鎖,你們只更新本身的那條,衝突的時候才排隊,這樣效率會高不少.安全

 

事務處理中行鎖的實例體驗:併發

set autocommit = 0;
update fa_admin set nickname = 'cyy' where id = 2;
commit;

 

innodb的索引與行級鎖

若是更新一個字段,而後在篩選的時候where後面的字段沒有加索引,就會把整個表的全部記錄都鎖定.高併發

在where後面的篩選字段加上索引後就不會鎖表只會鎖行,即便這個篩選範圍字段只是組合索引裏的其中一個測試

這裏我通過實際操做發現了個現象,當更新的時候若是以主鍵爲where條件,而且主鍵類型是varcahr的可是你在條件裏寫成int的了(都是數字,類型不一樣),第一個用戶沒有提交事務,會阻塞後面的用戶更新另外一條記錄.
因此這裏要注意,更新的時候必定要注意看清字段的類型寫sqlspa

 

索引對錶鎖的影響:code

alter table的語句是很危險的(其實他的危險實際上是未提交事物或者長事務致使的),在操做以前最好確認對要操做的表沒有任何進行中的操做、沒有未提交事務、也沒有顯式事務中的報錯語句。若是有alter table的維護任務,在無人監管的時候運行,最好經過lock_wait_timeout設置好超時時間,避免長時間的metedata鎖等待。blog

加索引要避免鎖表,須要先肯定此時沒有慢查詢事務未提交,若是這個查詢卡了30分鐘,那麼整個表的全部業務都會卡30分鐘,這是很變態的。

因此大表加索引仍是在沒人用的時間加比較安全,要不就是先建立副本,再將表名改掉。

由此得出一個結論,當一張表數據量很大時,不要輕易添加索引,會致使表被鎖死!若是非要添加,那麼應該先把數據表進行備份,而後進行空表添加索引。

 

查詢範圍對mysql鎖的影響:

set autocommit=0;
update fa_admin set nickname='cyy4' where id>1;

這種狀況下,執行insert操做,會存在阻塞,由於新增的id也在更新的範圍內;

set autocommit=0;
update fa_admin set nickname='cyy4' where id<3;

這種狀況下,不存在阻塞;

建議每次行鎖的範圍越小越好,這樣對其餘數據的阻塞就越小;

 

高併發下商城秒殺悲觀鎖的應用技巧:

當select XXXX for update就會鎖住這一行記錄,別人只能查不能更新,即加了寫鎖;

demo以下:

set autocommit=0;
select * from fa_admin where id = 1 for update;
update fa_admin set username = 'cyy6' where id = 1;
commit;

 

使用樂觀鎖控制高併發下商品下單:

方式1:使用數據版本(Version)記錄機制實現,這是樂觀鎖最經常使用的一種實現 方式。何謂數據版本?即爲數據增長一個版本標識,通常是經過爲數據庫表增長一個數字類型的 「version」 字段來實現。當讀取數據時,將version字段的值一同讀出,數據每更新一次,對此version值加一。當咱們提交更新的時候,判斷數據庫表對應記錄 的當前版本信息與第一次取出來的version值進行比對,若是數據庫表當前版本號與第一次取出來的version值相等,則予以更新,不然認爲是過時數據。

set autocommit=0;
select * from fa_admin where id = 1;
update fa_admin set nickname = 'cyy7',version = version + 1 where id = 1 and version = 0;
commit;

 

方式2:樂觀鎖定的第二種實現方式和第一種差很少,一樣是在須要樂觀鎖控制的table中增長一個字段,名稱無所謂,字段類型使用時間戳 (timestamp), 和上面的version相似,也是在更新提交的時候檢查當前數據庫中數據的時間戳和本身更新前取到的時間戳進行對比,若是一致則OK,不然就是版本衝突。

 

讀鎖與寫鎖的運轉:

讀鎖:只能讀,不能寫;select成功,insert失敗。

加鎖:lock table XX read
釋放鎖:unlock table
加上讀鎖後你們均可以查詢,對於當前加鎖的這個用戶來講,也只能查詢(讀),更新插入(寫)的時候就會報錯
對於其餘用戶來講能夠查詢,可是更新(寫)操做會被阻塞,直到加鎖的用戶釋放這個讀鎖

lock table fa_admin read;
select * from fa_admin;
insert into fa_admin(username) values('cyy8');
unlock tables;

寫鎖:既不能讀,也不能寫

在當前會話中能夠讀寫,別的會話不能讀也不能寫,都會被阻塞,直到當前會話釋放這個鎖

加鎖:lock table XXX write;
解鎖:unlock table;

在實際操做寫鎖的時候發現navicat一個查詢標籤在加了寫鎖後會把本身也鎖住,這操做騷的一批.

 
使用表鎖應用高併發下單實例:
 
首先建個測試表結構以下:

 

 隨便整點數據

 

 不建議表鎖

lock table goods write;
update goods set num = num - 200 where id = 1;
-- 寫單 發送 扣除餘額等 --
unlock tables;
相關文章
相關標籤/搜索