MySQL——Lock鎖

2020-10-06 12:00:44

InnoDB與MyISAM的最大不同有兩點:一是支援事務(TRANSACTION);二是採用了行級鎖。
檢視鎖命令:

show status like 'innodb_row_lock%';    

鎖分類

  • 讀鎖:也叫共用鎖、S鎖,若事務T對資料物件A加上S鎖,則事務T可以讀A但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S 鎖。這保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。

  • 寫鎖:又稱排他鎖、X鎖。若事務T對資料物件A加上X鎖,事務T可以讀A也可以修改A,其他事務不能再對A加任何鎖,直到T釋放A上的鎖。這保證了其他事務在T釋放A上的鎖之前不能再讀取和修改A。

  • 表鎖:操作物件是資料表。Mysql大多數鎖策略都支援(常見mysql innodb),是系統開銷最低但並行性最低的一個鎖策略。事務t對整個表加讀鎖,則其他事務可讀不可寫,若加寫鎖,則其他事務增刪改都不行。

  • 行級鎖:操作物件是資料表中的一行。是MVCC技術用的比較多的,但在MYISAM用不了,行級鎖用mysql的儲存引擎實現而不是mysql伺服器。但行級鎖對系統開銷較大,處理高並行較好。

MySQL不同的儲存引擎支援不同的鎖機制。
頁級:引擎 BDB。
表級:引擎 MyISAM , 理解為鎖住整個表,可以同時讀,寫不行
行級:引擎 INNODB , 單獨的一行記錄加鎖

  • 表級,直接鎖定整張表,在你鎖定期間,其它程序無法對該表進行寫操作。如果你是寫鎖,則其它程序則讀也不允許。開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,並行度最低。

  • 行級, 僅對指定的記錄進行加鎖,這樣其它程序還是可以對同一個表中的其它記錄進行操作。開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,並行度也最高。

  • 頁級,表級鎖速度快,但衝突多,行級衝突少,但速度慢。所以取了折衷的頁級,一次鎖定相鄰的一組記錄。開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,並行度一般

行鎖和表鎖

得出行鎖升級為表鎖的原因之一是: SQL 語句中未使用到索引,或者說使用的索引未被資料庫認可(相當於沒有使用索引)。
提出行鎖升級為表鎖與 事務的隔離級別 有關,並給出了事例。當然,我同意這個說法,因為事務的隔離性是靠加鎖來實現的,而加鎖勢必會影響並行。

我針對 「普通索引是表鎖」 進行了驗證,結果發現普通索引並不一定會引發表鎖,在普通索引中,是否引發表鎖取決於普通索引的高效程度(當索引欄位重複度高就會變成表鎖)。
結論:當「值重複率」低時,甚至接近主鍵或者唯一索引的效果,「普通索引」依然是行鎖;當「值重複率」高時,MySQL 不會把這個「普通索引」當做索引,即造成了一個沒有索引的 SQL,此時引發表鎖。

http://zhoupq.com/MySQL-避免行鎖升級為表鎖——使用高效的索引/

行鎖悲觀鎖的使用

要使用悲觀鎖,我們必須關閉mysql資料庫的自動提交屬性,因為MySQL預設使用autocommit模式,也就是說,當你執行一個更新操作後,MySQL會立刻將結果進行提交。

SELECT ... FOR UPDATE 實現悲觀鎖

show variables like "autocommit";
set autocommit=0;

//0.開始事務
begin;/begin work;/start transaction; (三者選一就可以)
//1.查詢出商品資訊
select status from t_goods where id=1 for update;
//2.根據商品資訊生成訂單
insert into t_orders (id,goods_id) values (null,1);
//3.修改商品status為2
update t_goods set status=2;
//4.提交事務
commit;/commit work;

注:需要注意的是,在事務中,只有SELECT … FOR UPDATE 或LOCK IN SHARE MODE 同一筆資料時會等待其它事務結束後才執行,一般SELECT … 則不受此影響。

來自:http://chenzhou123520.iteye.com/blog/1860954

當前讀:特殊的讀操作,插入/更新/刪除操作,屬於當前讀,處理的都是當前的資料,需要加鎖。

  • select * from table where ? lock in share mode;
  • select * from table where ? for update;
    來自:Innodb中的事務隔離級別和鎖的關係 https://tech.meituan.com/innodb-lock.html

樂觀鎖

hibernate中如何實現樂觀鎖:
前提:在現有表當中增加一個冗餘欄位,version版本號, long型別
原理:
1)只有當前版本號》=資料庫表版本號,才能提交
2)提交成功後,版本號version ++
先查詢,更新時帶上查詢條件去更新

來自:http://www.topthink.com/topic/815.html

表鎖

LOCK tables orders read local,order_detail read local;
SELECT SUM(total) FROM orders;
SELECT SUM(subtotal) FROM order_detail;
Unlock tables;

參考資料

MySQL中的鎖(表鎖、行鎖)