這篇文章主要講解了“MySQL中鎖的使用場景是什么”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Mysql中鎖的使用場景是什么”吧!
成都創(chuàng)新互聯(lián)從2013年開始,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務公司,擁有項目網(wǎng)站設(shè)計制作、成都做網(wǎng)站網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元息烽做網(wǎng)站,已為上家服務,為息烽各地企業(yè)和個人服務,聯(lián)系電話:13518219792
表級鎖,鎖定整張表
頁級鎖,鎖定一頁
行級鎖,鎖定一行
共享鎖,也叫S鎖,在MyISAM中也叫讀鎖
排他鎖,也叫X鎖,在MyISAM中也叫寫鎖
悲觀鎖,抽象性質(zhì),其實不真實存在
樂觀鎖,抽象性質(zhì),其實不真實存在
其實mysql中的引擎有很多種類,其中InnoDB和MyISAM引擎最常用
在mysql5.5版本前默認使用MyISAM引擎,之后使用InnoDB引擎
查看數(shù)據(jù)庫引擎命令如下
show variables like '%storage_engine%';
MyISAM 操作數(shù)據(jù)都是使用的表鎖,你更新一條記錄就要鎖整個表,導致性能較低,并發(fā)不高。當然同時它也不會存在死鎖問題。
而 InnoDB 與 MyISAM 的最大不同有兩點:一是 InnoDB 支持事務;二是 InnoDB 采用了行級鎖。
在 Mysql 中,行級鎖并不是直接鎖記錄,而是鎖索引。索引分為主鍵索引和非主鍵索引兩種,如果一條sql 語句操作了主鍵索引,Mysql 就會鎖定這條主鍵索引;如果一條語句操作了非主鍵索引,MySQL會先鎖定該非主鍵索引,再鎖定相關(guān)的主鍵索引。
InnoDB 行鎖是通過給索引項加鎖實現(xiàn)的,如果沒有索引,InnoDB 會通過隱藏的聚簇索引來對記錄加鎖。也就是說:如果不通過索引條件檢索數(shù)據(jù),那么InnoDB將對表中所有數(shù)據(jù)加鎖,實際效果跟表鎖一樣。因為沒有了索引,找到某一條記錄就得掃描全表,要掃描全表,就得鎖定表。
數(shù)據(jù)庫的增刪改操作默認都會加排他鎖,而查詢不會加任何鎖。
共享鎖:對某一資源加共享鎖,自身可以讀該資源,其他人也可以讀該資源(也可以再繼續(xù)加共享鎖,即 共享鎖可多個共存),但無法修改。要想修改就必須等所有共享鎖都釋放完之后。
排他鎖:對某一資源加排他鎖,自身可以進行增刪改查,其他人無法進行任何操作。
//共享鎖 select * from 表名 lock in share mode //排他鎖 select * from 表名 for update
這里我們以兩個操作數(shù)據(jù)庫的請求為例,假設(shè)這兩個請求分別為T1和T2
假設(shè)T1為查詢請求,而T2為更新數(shù)據(jù)請求,在T1查詢很長時間的時候,還沒有返回結(jié)果,但是這時候T2過來請求更新了
這個流程應該是: T1運行加共享鎖、T2運行、發(fā)現(xiàn)T1未完成等待其完成、T1完成、T2開始執(zhí)行
T2之所以要等待,是因為T2執(zhí)行更新的時候需要給表加排他鎖,但是數(shù)據(jù)庫規(guī)定,不能在同一資源上同時共存這兩種鎖,所以T2必須等T1執(zhí)行完,釋放鎖后,才可以正常操作
T1: select * from 表名 lock in share mode //假設(shè)還未返回結(jié)果 T2: update 表名 set name='autofelix'
如果T1和T2都是執(zhí)行的查詢,也就是都加共享鎖
這時候就不用等待,可以立馬執(zhí)行
因為同一資源上可以同時存在多個共享鎖,也被稱為,共享鎖與共享鎖兼容
意味著共享鎖不阻止其他人同時讀取資源,但是阻止其他人修改資源
T1: select * from table lock in share mode T2: select * from table lock in share mode
假設(shè)T1和T2都同時執(zhí)行2個資源操作,分別是查詢和更新數(shù)據(jù)
假設(shè)T1和T2同時達到select,T1對表加共享鎖,而T2也加上了共享鎖
當T1的select執(zhí)行完畢,準備執(zhí)行update時
根據(jù)鎖機制,T1的共享鎖必須升級到排他鎖才可以執(zhí)行接下來的update操作
在升級排他鎖之前,必須等T2的共享鎖釋放,同理,T2也在等T1的共享鎖釋放
于是都在等待對方的鎖釋放,導致程序卡死,這種情況就是死鎖
T1: 開啟事務,執(zhí)行查詢更新兩個操作 select * from table lock in share mode update table set column1='hello' T2: 開啟事務,執(zhí)行查詢更新兩個操作 select * from table lock in share mode update table set column1='world'
當T1和T2都是只執(zhí)行更新語句的時候
如下程序所示,這種語句非常的常見,很多人覺得他會產(chǎn)生死鎖,其實要看情況
如果id是主鍵,由于主鍵機制,并不需要全表掃描,直接可以更新當前數(shù)據(jù),所以不會產(chǎn)生死鎖
如果id是普通字段,那么當T1加上排他鎖之后,T2為了找到id=20條數(shù)據(jù),必須進行全表掃描,當他掃到第10條的時候,發(fā)現(xiàn)這里有排他鎖,導致全表掃描進行不下去,就會導致等待
T1: begin update table set content='hello' where id=10 T2: begin update table set content='world' where id=20
就是讓T1和T2順序執(zhí)行,比如T1在執(zhí)行完select后,立馬給自身加上排他鎖,這樣T2不得不等待T1執(zhí)行完才能繼續(xù)
但是如果有很多請求過來的話,都必須等待,這對用戶特別的不友好
所以,某些數(shù)據(jù)庫引入了另一種方式,叫做更新鎖,這里mysql除外,不存在更新鎖
更新鎖其實就是排他鎖的另一種實現(xiàn),只是他允許其他人讀的同時加共享鎖,但是不允許其他操作,除非釋放了更新鎖
流程大概如此: T1執(zhí)行完select加上更新鎖,T2執(zhí)行查詢完,準備加更新鎖,發(fā)現(xiàn)已經(jīng)有了,就等待,其他請求過來,如果查詢是不受影響的,但是更新才等待
這相比上面的查詢也要等待增加了效率
T1: begin select * from table for update update table set content='hello' T2: begin select * from table for update update table set content='world'
T1: begin select * from table [加更新鎖操作] update table set content='hello' T2: begin select * from table [加更新鎖操作] update table set content='world'
計劃鎖與程序猿無關(guān),不需要了解
意向鎖,Innodb特有,分為意向共享鎖和意向排他鎖
意向共享鎖: 表示事務獲取共享鎖時,必須先得獲取該表的意向共享鎖
意向排他鎖: 表示事務獲取排他鎖時,必須先得獲取該表的意向排他鎖
我們知道要對整個表加鎖,必須保證表內(nèi)不存在任何鎖
如果一行行的去檢查是否加鎖,效率必然極低,這時候可以檢測意向鎖是否被占用即可
樂觀鎖和悲觀鎖都是針對select而言的
比如在商品搶購中,用戶購買后庫存需要減1,而很多用戶同時購買時,讀出來的庫存數(shù)量一樣,然后多個用戶同時用該庫存去減1
這種做法必然會出現(xiàn)很大的漏洞,如果向在淘寶,京東出現(xiàn)這種情況,你就可以打包回家種地了
這種情況如何解決呢,其實可以使用悲觀鎖進行解決,說白了也就是排他鎖
用戶進來查庫存的時候,就加上排他鎖,等他所有操作完成后,再釋放排他鎖,讓其他人進來
不讓用戶等待,就可以使用樂觀鎖方式解決,樂觀鎖一般靠表的設(shè)計和時間戳來實現(xiàn)
一般是在表中添加version或者timestamp時間戳字段
這樣就會保證如果更新失敗,就表示有其他程序更新了數(shù)據(jù)庫,就可以通過重試解決
update table set num=num-1 where id=10 and version=12
感謝各位的閱讀,以上就是“Mysql中鎖的使用場景是什么”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對Mysql中鎖的使用場景是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!