爲何要加鎖?java
問題背景mysql
要解決的問題面試
鎖是什麼sql
鎖的分類數據庫
行bash
表微信
頁多線程
MySQL經常使用存儲引擎的鎖機制架構
MyISAM和MEMORY採用表級鎖(table-level locking)併發
BDB採用頁面鎖(page-level locking)或表級鎖,默認爲頁面鎖
InnoDB支持行級鎖(row-level locking)和表級鎖,默認爲行級鎖
在實際應用中,要特別注意InnoDB行鎖的這一特性,否則的話,可能致使大量的鎖衝突,從而影響併發性能。
行級鎖都是基於索引的,若是一條SQL語句用不到索引是不會使用行級鎖的,會使用表級鎖。行級鎖的缺點是:因爲須要請求大量的鎖資源,因此速度慢,內存消耗大。
實例說明
select語句默認不會加任何鎖類型,若是加排他鎖可使用select …for update語句,加共享鎖可使用select … lock in share mode語句。
因此加過排他鎖的數據行在其餘事務種是不能修改數據的,也不能經過for update和lock in share mode鎖的方式查詢數據,但能夠直接經過select …from…查詢數據,由於普通查詢沒有任何鎖機制。
行級鎖與死鎖
MyISAM中是不會產生死鎖的,由於MyISAM老是一次性得到所需的所有鎖,要麼所有知足,要麼所有等待。而在InnoDB中,鎖是逐步得到的,就形成了死鎖的可能。
在MySQL中,行級鎖並非直接鎖記錄,而是鎖索引。索引分爲主鍵索引和非主鍵索引兩種,若是一條sql語句操做了主鍵索引,MySQL就會鎖定這條主鍵索引;若是一條語句操做了非主鍵索引,MySQL會先鎖定該非主鍵索引,再鎖定相關的主鍵索引。在UPDATE、DELETE操做時,MySQL不只鎖定WHERE條件掃描過的全部索引記錄,並且會鎖定相鄰的鍵值,即所謂的next-key locking。
當兩個事務同時執行,一個鎖住了主鍵索引,在等待其餘相關索引。另外一個鎖定了非主鍵索引,在等待主鍵索引。這樣就會發生死鎖。
發生死鎖後,InnoDB通常均可以檢測到,並使一個事務釋放鎖回退,另外一個獲取鎖完成事務。
共享鎖與排它鎖
共享鎖(Share Lock)
若是事務T對數據A加上共享鎖後,則其餘事務只能對A再加共享鎖,不能加排他鎖。獲准共享鎖的事務只能讀數據,不能修改數據。
用法 SELECT ... LOCK IN SHARE MODE;
在查詢語句後面增長LOCK IN SHARE MODE,Mysql會對查詢結果中的每行都加共享鎖,當沒有其餘線程對查詢結果集中的任何一行使用排他鎖時,能夠成功申請共享鎖,不然會被阻塞。其餘線程也能夠讀取使用了共享鎖的表,並且這些線程讀取的是同一個版本的數據。
排它鎖(eXclusive Lock)
用法 SELECT ... FOR UPDATE;
在查詢語句後面增長FOR UPDATE,Mysql會對查詢結果中的每行都加排他鎖,當沒有其餘線程對查詢結果集中的任何一行使用排他鎖時,能夠成功申請排他鎖,不然會被阻塞。
樂觀鎖(Optimistic Lock)
是什麼
相對於悲觀鎖,在對數據庫進行處理的時候,樂觀鎖並不會使用數據庫提供的鎖機制。通常的實現樂觀鎖的方式就是記錄數據版本。
數據版本,爲數據增長的一個版本標識。當讀取數據時,將版本標識的值一同讀出,數據每更新一次,同時對版本標識進行更新。當咱們提交更新的時候,判斷數據庫表對應記錄的當前版本信息與第一次取出來的版本標識進行比對,若是數據庫表當前版本號與第一次取出來的版本標識值相等,則予以更新,不然認爲是過時數據。
實現數據版本有兩種方式,第一種是使用版本號,第二種是使用時間戳。
使用版本號實現樂觀鎖
1.查詢出商品信息select (status,status,version) from t_goods where id=#{id}2.根據商品信息生成訂單3.修改商品status爲2update t_goodsset status=2,version=version+1where id=#{id} and version=#{version};複製代碼
優勢與不足
悲觀鎖(Pessimistic Lock)
是什麼
悲觀鎖的流程
MySQL InnoDB中使用悲觀鎖
//0.開始事務begin;//1.查詢出商品信息select status from t_goods where id=1 for update;//2.根據商品信息生成訂單insert into t_orders (id,goods_id) values (null,1);//3.修改商品status爲2update t_goods set status=2;//4.提交事務commit;複製代碼
上面的查詢語句中,咱們使用了select…for update的方式,這樣就經過開啓排他鎖的方式實現了悲觀鎖。此時在t_goods表中,id爲1的 那條數據就被咱們鎖定了,其它的事務必須等本次事務提交以後才能執行。這樣咱們能夠保證當前的數據不會被其它事務修改。
Java的鎖機制
線程的同步問題
線程的同步方法:
ThreadLocal
當使用ThreadLocal維護變量時,ThreadLocal爲每一個使用該變量的線程提供獨立的變量副本,因此每個線程均可以獨立地改變本身的副本,而不會影響其它線程所對應的副本。在ThreadLocal類中有一個Map,用於存儲每個線程的變量副本,Map中元素的鍵爲線程對象,而值對應線程的變量副本。使用ThreadLocal的典型場景如數據庫鏈接管理,線程會話管理等場景,只適用於獨立變量副本的狀況,若是變量爲全局共享的,則不適用在高併發下使用。
最後給你們分享一些學習資料,裏面包括:(BATJ面試資料、高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)和Java進階學習路線圖。
領取方式:加微信號 weixin99ting 備註 :(資料) 便可獲取。
最後,祝你們早日學有所成!