首頁  >  文章  >  資料庫  >  詳細解析mysql鎖機制

詳細解析mysql鎖機制

WBOY
WBOY轉載
2022-03-16 17:33:022138瀏覽

這篇文章為大家帶來了關於mysql的相關知識,其中主要介紹了mysql中各種鎖的機制問題,鎖是資料庫為了保證資料的一致性,而使用各種共享的資源在被並發存取時變得有序所設計的一種規則,希望對大家有幫助。

詳細解析mysql鎖機制

推薦學習:mysql教學

#Mysql鎖定:

在多執行緒當中如果想保證資料的準確性是如何實現的呢?沒錯,透過同步實現。同步就相當於加鎖。加了鎖以後有什麼好處呢?當一個執行緒真正在操作資料的時候,其他執行緒只能等待。當一個執行緒執行完畢後,釋放鎖定。其他線程才能進行操作!

那麼我們的MySQL資料庫中的鎖定的功能也是類似的,處理事務的隔離性中,可能會出現髒讀、不可重複讀取、幻讀的問題,所以,鎖的作用也可以解決這些問題!

在資料庫中,資料是許多使用者共享存取的資源,如何保證資料並發存取的一致性、有效性,是所有資料庫必須解決的問題,MySQL由於自身架構的特點,在不同的儲存引擎中,都設計了面對特定場景的鎖定機制,所以引擎的差別,導致鎖定機制也是有很大差別的。

鎖定機制 :

資料庫為了確保資料的一致性,而使用各種共享的資源在被並發存取時變得有序所設計的一種規則。

舉例:在電商網站購買商品時,商品表中只存有1個商品,而此時又有兩個人同時購買,那麼誰能買到就是一個關鍵的問題。

這裡會用到交易進行一系列的操作:

先從商品表中取出物品的資料

然後插入訂單

付款後,再插入付款表資訊

更新商品表中商品的數量

#以上過程中,使用鎖定可以對商品數量資料資訊進行保護,實現隔離,即只允許第一位使用者完成整套購買流程,而其他使用者只能等待,這樣就解決了並發中的矛盾問題。

鎖定的分類:

依動作分類:

#共享鎖定:也叫讀鎖定。針對同一份數據,多個事務讀取操作可以同時加鎖而不互相影響 ,但是不能修改數據記錄。

排他鎖:也叫寫鎖。目前的操作沒有完成前,會阻斷其他操作的讀取和寫入

按粒度分類:

##表級鎖定:操作時,會鎖定整個表。開銷小,加鎖快;不會出現死鎖;鎖定力道大,發生鎖衝突機率高,並發度最低。偏向MyISAM儲存引擎!

行級鎖定:操作時,會鎖定目前操作行。開銷大,加鎖慢;會出現死鎖;鎖定粒度小,發生鎖衝突的機率低,並發度高。偏向InnoDB儲存引擎!

頁級鎖定:鎖的粒度、發生衝突的機率和加鎖的開銷介於表鎖和行鎖之間,會出現死鎖,並發效能一般。

以使用方式分類:

悲觀鎖定:每次查詢資料時都認為別人會修改,很悲觀,所以查詢時會加鎖。

樂觀鎖:每次查詢資料時都認為別人不會修改,很樂觀,但是更新時會判斷一下在此期間別人有沒有去更新這個資料

不同儲存引擎支持的鎖

詳細解析mysql鎖機制

共享鎖定:

多個共享鎖之間可以共享,如果是有鍵的話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讀取鎖:

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学习教程

以上是詳細解析mysql鎖機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除