1. 程式人生 > >MyISAM鎖 與 INNODB鎖

MyISAM鎖 與 INNODB鎖

本文雙引號內容為重要點 ,在markdown中雙引號的內容為紅色

一 MyISAM鎖

表鎖

表鎖:不會出現死鎖,容易發生鎖衝突,併發低

(1) 表鎖的兩種模式: "表共享鎖 (Table Read Lock)" 和 "表獨佔寫鎖 (Table Write Lock)"

 注: 
    共享鎖,不會阻塞其他使用者對同一表的讀請求,但會阻塞對同一表的寫請求;
    獨佔寫鎖,則會阻塞其他使用者對同一表的讀和寫請求;
    讀操作和寫操作之間,以及寫操作之間是序列的;
    "當一執行緒獲得對一個表的寫鎖後,只有持有鎖的執行緒可以對錶進行更新操作。其他執行緒的讀、寫操作都會等待,直到鎖被釋放為止。"
    
(2) 如何加鎖:MyISAM在sql查詢時會將涉及到的表加上讀鎖,在執行插入或更新時會加寫鎖。使用者也可以用LOCK TABLE去顯式的加鎖。

 示例:
     LOCK tables orders read local,order_detail read local;   加鎖
     SELECT SUM(total) FROM orders;
     SELECT SUM(subtotal) FROM order_detail;
     UNLOCK tables;                                           解鎖
     
     "local"選項作用是滿足MYISAM併發插入條件的情況下,允許其他使用者在表尾插入記錄,若不加"local"選項,則不允許。
 注:
    顯式的加鎖一般是應用於:需要在一個時間點實現多個表的一致性讀取。不然的話,可能讀第一個表時,其他表由於還沒進行讀操作,
沒有自動加鎖,可能資料會發生改變。並且顯示加鎖後只能訪問加鎖的表,不能訪問其他表。
 

併發鎖

    併發鎖:在一定條件下MYISAM支援查詢與插入併發執行
    條件:MYISAM引擎系統變數concurrent_insert
    值:
        0 不允許併發插入
        1 程序在讀取表的時候允許另一個程序在表尾插入記錄, MySQL預設設定
        2 無論MYISAM表中有沒有空洞,都允許在表尾插入記錄,也允許併發插入記錄表    
             
    空洞:指表中的資料出現斷層

鎖的排程情況

預設情況:
        MyISAM儲存引擎的讀和寫鎖是互斥,讀操作是序列的。在沒有做任何調整的情況下,寫程序會比讀程序
    優先獲得鎖,即使讀程序優先於寫程序請求。

    大量的更新操作會造成查詢操作很難獲取到讀鎖,從而導致永遠阻塞情況。
    
    "MySQL認為寫請求一般比讀請求重要"
    
調整方式:
    通過"low-priority-updates" 引數,使MyISAM引擎預設給予讀請求以優先的權利。
    通過執行命令SET LOW_PRIORITY_UPDATES=1,使該連線發出的更新請求優先順序降低。
    通過指定INSERT、UPDATE、DELETE語句的LOW_PRIORITY屬性,降低該語句的優先順序

二 INNODB鎖

行鎖

行鎖:會出現死鎖,發生鎖衝突機率低,併發高

"mysql的行鎖是通過索引載入的,要是對了的sql語句沒有走索引,則會全表掃描,行鎖無法實現,取而代之的是表鎖。"

(1) 行鎖的兩種模式: "共享鎖(S)" 和 "排他鎖(X)"
    
    注:
        共享鎖(S):當一個事務對某幾行上讀鎖時,允許其他事務對這幾行進行讀操作,
        但不允許其進行寫操作,也不允許其他事務給這幾行上排它鎖,但允許上讀鎖。

        排它鎖(X):當一個事務對某幾個上寫鎖時,不允許其他事務寫,但允許讀。更不允許其他事務給這幾行上任何鎖。
        另外,為了允許行鎖和表鎖共存,實現多粒度鎖機制,InnoDB還有兩種內部使用的意向鎖,這兩種"意向鎖都是表鎖"。
        
        衍生:
            意向共享鎖(IS):事務打算給資料行加行共享鎖,事務在給一個數據行加共享鎖前必須先取得該表的IS鎖。
            意向排他鎖(IX):事務打算給資料行加行排他鎖,事務在給一個數據行加排他鎖前必須先取得該表的IX鎖。
        
    示例:
         select math from zje where math > 60 "lock in share mode";  共享鎖
         select math from zje where math > 60 "for update";          排他鎖
         
    重點:
        1.行鎖必須有索引才能實現,否則會自動鎖全表,那麼就不是行鎖了。
        2.兩個事務不能鎖同一個索引。
            示例:
                事務A先執行:
                select math from zje where math > 60 for update;
                事務B再執行:
                select math from zje where math < 60 for update;
                這樣的話,事務B是會阻塞的。如果事務B把 math索引換成其他索引就不會阻塞。
                但注意,換成其他索引鎖住的行不能和math索引鎖住的行有重複。
        3.insert ,delete , update在事務中都會自動預設加上排它鎖。
       

鎖衝突

示例:
    事務A將某幾行上鎖後,事務B又對其上鎖,鎖不能共存否則會出現鎖衝突。
   (但是共享鎖可以共存,共享鎖和排它鎖不能共存,排它鎖和排他鎖也不可以)

死鎖

示例:
    兩個事務,事務A鎖住了1~5行,同時事務B鎖住了6~10行,此時事務A請求鎖住6~10行,就會阻塞直到事務B施放6~10行的鎖,
而隨後事務B又請求鎖住1~5行,事務B也阻塞直到事務A釋放1~5行的鎖。死鎖發生時,會產生Deadlock錯誤。

問題

為什麼表鎖不會產生死鎖?
答:鎖對錶進行操作,將全表鎖住之後自然就不會產生死鎖

樂觀鎖

    操作資料庫時(更新操作),想法很樂觀,認為這次的操作不會導致衝突。"(一般都需要自己去實現)"
    
    示例:
        下單操作包括3步驟:

        1.查詢出商品資訊
        
        select (status,status,"version") from t_goods where id=#{id}
        
        2.根據商品資訊生成訂單
        
        3.修改商品status為2
        
        update t_goods 
        
        set status=2,version=version+1
        
        where id=#{id} and "version=#{version}";

    注:實現樂觀鎖與例項中的紅色字型相關

悲觀鎖

    操作資料時,認為此操作會出現資料衝突,所以在進行每次操作時都要通過獲取鎖才能進行對相同資料的操作,
這點跟java中的synchronized很相似,所以悲觀鎖需要耗費較多的時間。
    
    "共享鎖和排它鎖是悲觀鎖的不同的實現"