您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“mysql鎖機制的概念是什么”,內容詳細,步驟清晰,細節處理妥當,希望這篇“mysql鎖機制的概念是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
在多線程當中如果想保證數據的準確性是如何實現的呢?沒錯,通過同步實現。同步就相當于是加鎖。加了鎖以后有什么好處呢?當一個線程真正在操作數據的時候,其他線程只能等待。當一個線程執行完畢后,釋放鎖。其他線程才能進行操作!
那么我們的MySQL數據庫中的鎖的功能也是類似的,處理事務的隔離性中,可能會出現臟讀、不可重復讀、幻讀的問題,所以,鎖的作用也可以解決這些問題!
在數據庫中,數據是一種供許多用戶共享訪問的資源,如何保證數據并發訪問的一致性、有效性,是所有數據庫必須解決的一個問題,MySQL由于自身架構的特點,在不同的存儲引擎中,都設計了面對特定場景的鎖定機制,所以引擎的差別,導致鎖機制也是有很大差別的。
數據庫為了保證數據的一致性,而使用各種共享的資源在被并發訪問時變得有序所設計的一種規則。
舉例:在電商網站購買商品時,商品表中只存有1個商品,而此時又有兩個人同時購買,那么誰能買到就是一個關鍵的問題。
這里會用到事務進行一系列的操作:
先從商品表中取出物品的數據
然后插入訂單
付款后,再插入付款表信息
更新商品表中商品的數量
以上過程中,使用鎖可以對商品數量數據信息進行保護,實現隔離,即只允許第一位用戶完成整套購買流程,而其他用戶只能等待,這樣就解決了并發中的矛盾問題。
按操作分類:
共享鎖:也叫讀鎖。針對同一份數據,多個事務讀取操作可以同時加鎖而不互相影響 ,但是不能修改數據記錄。
排他鎖:也叫寫鎖。當前的操作沒有完成前,會阻斷其他操作的讀取和寫入
按粒度分類:
表級鎖:操作時,會鎖定整個表。開銷小,加鎖快;不會出現死鎖;鎖定力度大,發生鎖沖突概率高,并發度最低。偏向于MyISAM存儲引擎!
行級鎖:操作時,會鎖定當前操作行。開銷大,加鎖慢;會出現死鎖;鎖定粒度小,發生鎖沖突的概率低,并發度高。偏向于InnoDB存儲引擎!
頁級鎖:鎖的粒度、發生沖突的概率和加鎖的開銷介于表鎖和行鎖之間,會出現死鎖,并發性能一般。
按使用方式分類:
悲觀鎖:每次查詢數據時都認為別人會修改,很悲觀,所以查詢時加鎖。
樂觀鎖:每次查詢數據時都認為別人不會修改,很樂觀,但是更新時會判斷一下在此期間別人有沒有去更新這個數據
不同存儲引擎支持的鎖
多個共享鎖之間可以共享,如果是有鍵的話InnoDB默認是行鎖,沒有的話就會提升到表鎖,是行鎖時多個窗口可以修改不同行的數據,同行的話需要等先加鎖的提交,不同行可以直接修改,但是另外一個要查詢也要等后面修改的提交。提交完鎖就消失了
共享鎖:
SELECT語句 LOCK IN SHARE MODE;
窗口1:
- 窗口1 /* 共享鎖:數據可以被多個事務查詢,但是不能修改 */ -- 開啟事務 START TRANSACTION; -- 查詢id為1的數據記錄。加入共享鎖 SELECT * FROM student WHERE id=1 LOCK IN SHARE MODE; -- 查詢分數為99分的數據記錄。加入共享鎖 SELECT * FROM student WHERE score=99 LOCK IN SHARE MODE; -- 提交事務 COMMIT;
窗口2:
-- 窗口2 -- 開啟事務 START TRANSACTION; -- 查詢id為1的數據記錄(普通查詢,可以查詢) SELECT * FROM student WHERE id=1; -- 查詢id為1的數據記錄,并加入共享鎖(可以查詢。共享鎖和共享鎖兼容) SELECT * FROM student WHERE id=1 LOCK IN SHARE MODE; -- 修改id為1的姓名為張三三(不能修改,會出現鎖的情況。只有窗口1提交事務后,才能修改成功) UPDATE student SET NAME='張三三' WHERE id = 1; -- 修改id為2的姓名為李四四(修改成功,InnoDB引擎默認是行鎖) UPDATE student SET NAME='李四四' WHERE id = 2; -- 修改id為3的姓名為王五五(修改失敗,InnoDB引擎如果不采用帶索引的列加鎖。則會提升為表鎖) UPDATE student SET NAME='王五五' WHERE id = 3; -- 提交事務 COMMIT;
排他鎖:
在排他鎖執行的時候,其他事務普通查詢可以,不可以加鎖任何操作
-- 標準語法 SELECT語句 FOR UPDATE;
窗口1:
-- 窗口1 /* 排他鎖:加鎖的數據,不能被其他事務加鎖查詢或修改 */ -- 開啟事務 START TRANSACTION; -- 查詢id為1的數據記錄,并加入排他鎖 SELECT * FROM student WHERE id=1 FOR UPDATE; -- 提交事務 COMMIT;
窗口2:
-- 窗口2 -- 開啟事務 START TRANSACTION; -- 查詢id為1的數據記錄(普通查詢沒問題) SELECT * FROM student WHERE id=1; -- 查詢id為1的數據記錄,并加入共享鎖(不能查詢。因為排他鎖不能和其他鎖共存) SELECT * FROM student WHERE id=1 LOCK IN SHARE MODE; -- 查詢id為1的數據記錄,并加入排他鎖(不能查詢。因為排他鎖不能和其他鎖共存) SELECT * FROM student WHERE id=1 FOR UPDATE; -- 修改id為1的姓名為張三(不能修改,會出現鎖的情況。只有窗口1提交事務后,才能修改成功) UPDATE student SET NAME='張三' WHERE id=1; -- 提交事務 COMMIT;
MyISAM讀鎖:
myisam是加整個表的鎖,讀鎖的時候,不解鎖的話所有的事務可以查,不可以有其他任何操作包括本身事務也不可以操作
-- 加鎖 LOCK TABLE 表名 READ; -- 解鎖(將當前會話所有的表進行解鎖) UNLOCK TABLES;
MyISAM寫鎖:
寫鎖的時候,只要不解鎖其他事務不可以執行任何操作,本身事務可以操作
-- 標準語法 -- 加鎖 LOCK TABLE 表名 WRITE; -- 解鎖(將當前會話所有的表進行解鎖) UNLOCK TABLES;
悲觀鎖:
就是很悲觀,它對于數據被外界修改的操作持保守態度,認為數據隨時會修改。
整個數據處理中需要將數據加鎖。悲觀鎖一般都是依靠關系型數據庫提供的鎖機制。
行鎖,表鎖不論是讀寫鎖都是悲觀鎖。
樂觀鎖:
就是很樂觀,每次自己操作數據的時候認為沒有人會來修改它,所以不去加鎖。
但是在更新的時候會去判斷在此期間數據有沒有被修改。
需要用戶自己去實現,不會發生并發搶占資源,只有在提交操作的時候檢查是否違反數據完整性。
樂觀鎖的簡單實現方式:
實現思想:加標記去比較,一樣則執行,不同則不執行
方式一:版本號
給數據表中添加一個version列,每次更新后都將這個列的值加1。
讀取數據時,將版本號讀取出來,在執行更新的時候,比較版本號。
如果相同則執行更新,如果不相同,說明此條數據已經發生了變化。
用戶自行根據這個通知來決定怎么處理,比如重新開始一遍,或者放棄本次更新。
-- 創建city表 CREATE TABLE city( id INT PRIMARY KEY AUTO_INCREMENT, -- 城市id NAME VARCHAR(20), -- 城市名稱 VERSION INT -- 版本號 ); -- 添加數據 INSERT INTO city VALUES (NULL,'北京',1),(NULL,'上海',1),(NULL,'廣州',1),(NULL,'深圳',1); -- 修改北京為北京市 -- 1.查詢北京的version SELECT VERSION FROM city WHERE NAME='北京'; -- 2.修改北京為北京市,版本號+1。并對比版本號 UPDATE city SET NAME='北京市',VERSION=VERSION+1 WHERE NAME='北京' AND VERSION=1;
方式二:時間戳
和版本號方式基本一樣,給數據表中添加一個列,名稱無所謂,數據類型需要是timestamp
每次更新后都將最新時間插入到此列。
讀取數據時,將時間讀取出來,在執行更新的時候,比較時間。
如果相同則執行更新,如果不相同,說明此條數據已經發生了變化。
悲觀鎖和樂觀鎖使用前提:
對于讀的操作遠多于寫的操作的時候,這時候一個更新操作加鎖會阻塞所有的讀取操作,降低了吞吐量。最后還要釋放鎖,鎖是需要一些開銷的,這時候可以選擇樂觀鎖。
如果是讀寫比例差距不是非常大或者系統沒有響應不及時,吞吐量瓶頸的問題,那就不要去使用樂觀鎖,它增加了復雜度,也帶來了業務額外的風險。這時候可以選擇悲觀鎖。
讀到這里,這篇“mysql鎖機制的概念是什么”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。