日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

浅析SQL Server在可序列化隔离级别下,防止幻读的范围锁的锁定问题

發(fā)布時(shí)間:2025/3/21 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅析SQL Server在可序列化隔离级别下,防止幻读的范围锁的锁定问题 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

本文出處:http://www.cnblogs.com/wy123/p/7501261.html?
(保留出處并非什么原創(chuàng)作品權(quán)利,本人拙作還遠(yuǎn)遠(yuǎn)達(dá)不到,僅僅是為了鏈接到原文,因?yàn)楹罄m(xù)對(duì)可能存在的一些錯(cuò)誤進(jìn)行修正或補(bǔ)充,無(wú)他)

?

?

數(shù)據(jù)庫(kù)在處理并發(fā)事物的過(guò)程中,在不同的隔離級(jí)別下有不同的鎖表現(xiàn),在非可序列化隔離級(jí)別下,存在著臟讀,不可重復(fù)讀,丟失更新,幻讀等情況。
本文不討論臟讀和不可重復(fù)讀以及丟失更新的情形,僅討論幻讀,幻讀是指在一個(gè)事物中,同一個(gè)條件,存在兩次讀到的數(shù)據(jù)行數(shù)不一致的情況。
最高隔離級(jí)別也即可序列化隔離級(jí)別消除了幻讀,幻讀的消除過(guò)程中會(huì)通過(guò)Range鎖(也即范圍鎖)來(lái)實(shí)現(xiàn)事物隔離的。
那么,Range鎖是如何產(chǎn)生的?產(chǎn)生Range鎖時(shí),鎖定的范圍又是如何確定的?不同的索引產(chǎn)生的Range鎖范圍有什么區(qū)別?
本文將對(duì)此進(jìn)行一個(gè)粗淺的分析與推斷。


查閱了很多資料,尚未得到一個(gè)非常清晰的答案,原因在于:

1,沒(méi)有指明Range鎖的范圍,觀察鎖的時(shí)候看到Range鎖產(chǎn)生之后就收?qǐng)?#xff0c;并沒(méi)有分析Range鎖產(chǎn)生時(shí),鎖定的具體范圍是什么,鎖定已存在的值沒(méi)問(wèn)題,是否鎖定未存在的值?
1,非唯一索引與唯一索引的情況下產(chǎn)生的范圍鎖,鎖定的范圍包不包括臨界值 ?
2,對(duì)于查詢表中不存在的key值(分兩種,一種是介于表中最大與最小Key之間,一種是位于最大或者最小key值之外),鎖定的范圍到底是怎么樣的?

?

測(cè)試中發(fā)現(xiàn)一個(gè)有意思的問(wèn)題,對(duì)于唯一索引,當(dāng)鎖定目標(biāo)是一個(gè)表中已存在的Key值的時(shí)候,表面上產(chǎn)生的是一個(gè)key鎖,真的就僅僅鎖定了當(dāng)前的這一個(gè)Key(數(shù)據(jù)行)嗎?

同時(shí),對(duì)于那個(gè)經(jīng)典的“并發(fā)情況下存在則更新,不存在的插入”的處理,其背后的原理,也可以用Range鎖來(lái)解釋。

?

說(shuō)明一下本文測(cè)試的原則:
1,測(cè)試均在可序列化隔離級(jí)別下測(cè)試(set transaction isolation level serializable?)。
2,測(cè)試的原則是,Session1中采用排它鎖的方式加鎖,利用共享鎖與排它鎖不兼容的特點(diǎn),Session2中采用共享鎖的方式來(lái)不斷探測(cè)Session1中產(chǎn)生的鎖的范圍。
3,測(cè)試數(shù)據(jù)庫(kù)是SQL Server 2014

?

1,測(cè)試環(huán)境構(gòu)建

  1.1 ?新建測(cè)試表并寫(xiě)入數(shù)據(jù)

create table TestLock (Id int,Name varchar(100) )create clustered index idx_id on TestLock(id)insert into TestLock values (10,'aaa') insert into TestLock values (20,'bbb') insert into TestLock values (30,'ccc') insert into TestLock values (40,'ddd') insert into TestLock values (50,'eee')

1.2 測(cè)試表中的數(shù)據(jù)行存儲(chǔ)位置分析?

通過(guò)系統(tǒng)命令或者表查詢測(cè)試表的page信息

--查看數(shù)據(jù)頁(yè)信息 dbcc ind('Test','TestLock',-1) --或者查詢系統(tǒng)DMV select * from sys.dm_db_database_page_allocations(db_id('Test'),object_id('TestLock'),null,null,'detailed')

表TestLock的數(shù)據(jù)頁(yè)面為147

  1.3 查詢147號(hào)頁(yè)面的數(shù)據(jù)行的KeyHashValue(可以認(rèn)為是數(shù)據(jù)行的唯一標(biāo)識(shí))

DBCC TRACEON(3604) DBCC PAGE(Test,1,147,3)

?  這里找到數(shù)據(jù)行對(duì)應(yīng)的KeyHashValue如下圖所示

  整理出來(lái)的數(shù)據(jù)行Id與其對(duì)應(yīng)的KeyHashValue如下

10:241332e1ddb0
20:69c872e07e60
30:0bdec3f2b948
40:199f61d4d268
50:0878442f3a75

?

2,Range鎖產(chǎn)生時(shí),鎖定的范圍初步分析

  2.1 Range鎖產(chǎn)生的場(chǎng)景分析

  在可序列化隔離級(jí)別下,測(cè)試一個(gè)Range鎖產(chǎn)生的情況
  如代碼中的備注所示,第一個(gè)Session中執(zhí)行如下查詢,暫不提交事物

  

?  ?第一個(gè)Session中執(zhí)行情況先保持(不提交也不回滾),另開(kāi)一個(gè)查詢窗口,也即第二個(gè)Session中查詢產(chǎn)生的Range鎖

  

可以清楚地看到產(chǎn)生兩個(gè)Range鎖的resource_description分別是0bdec3f2b948和199f61d4d268
對(duì)照上面分析出來(lái)的數(shù)據(jù)行與KeyHashValue的關(guān)系,說(shuō)明這個(gè)兩個(gè)resource_description的值分別是30和40
最重要的問(wèn)題就在這里,Range鎖的resource_description是0bdec3f2b948和199f61d4d268,既然是RangeX-X,也就是范圍鎖,那么這兩個(gè)Range鎖定的范圍是多大?
這里先給出結(jié)論,當(dāng)在產(chǎn)生key類(lèi)型的Range鎖的時(shí)候,
以上述測(cè)試case為例,每一個(gè)Range鎖對(duì)應(yīng)的范圍如下(以下表格內(nèi)容都包括臨界值,臨界值跟索引是否唯一也有關(guān),下文會(huì)有說(shuō)明)

  

以上述測(cè)試為例,產(chǎn)生了兩個(gè)RangeX-X類(lèi)型的Key類(lèi)型鎖,分別是Id為30和40對(duì)應(yīng)的RangeX-X,那么鎖定的范圍就是20~40,
既然是一個(gè)范圍鎖,就跟表中是區(qū)間的數(shù)據(jù)是否存在無(wú)關(guān)。
上面的話怎么理解?
如何證明鎖定的范圍就是20~40,看以下測(cè)試:

?

  2.2查詢被鎖定區(qū)間的值,不管這個(gè)值是否已經(jīng)存在于表中,都是會(huì)被被阻塞的

  Session2中以序列化隔離級(jí)別執(zhí)行如下代碼,
  查詢Id = 35的Id值,雖然Id = 35是一個(gè)不存在的值,但是這個(gè)區(qū)間被鎖定了,按道理,查詢Id = 35的查詢是會(huì)被阻塞的。
  測(cè)試正如所預(yù)料的,因?yàn)檫@個(gè)區(qū)間被鎖定了(排它鎖),查詢這個(gè)區(qū)間的任何一個(gè)值都被阻塞,而不管查詢的Id值是否存在

  

  繼續(xù)測(cè)試,回滾Session2中的查詢,查詢一個(gè)下限范圍的Id,
  同樣的道理,雖然Id = 25是一個(gè)不存在的值,但是這個(gè)區(qū)間被鎖定了,按道理,查詢Id = 25的查詢是會(huì)被阻塞的。
  也是正如所預(yù)料的,因?yàn)檫@個(gè)區(qū)間被鎖定了(排它鎖),查詢這個(gè)區(qū)間的任何一個(gè)值都被阻塞,而不管查詢的Id值是否存在

  

  

  2.3查詢非鎖定區(qū)間的值,不管這個(gè)值是否已經(jīng)存在于表中,都是不會(huì)被被阻塞的

  上面說(shuō)了,鎖定的范圍就是20~40,那么查詢一個(gè)非此區(qū)間的Id,是不會(huì)被鎖定的。
  繼續(xù)測(cè)試,回滾Session2的查詢,查詢一個(gè)Id = 50的值,在非鎖定范圍之內(nèi)(也即非20~40這個(gè)區(qū)間的Id),是可以正常查詢的,也是預(yù)期的。

  

  繼續(xù)回滾Session2中的查詢,查詢一個(gè)小于20且存在的Id值,查詢成功

  

  繼續(xù)回滾Session2中的查詢,查詢一個(gè)小于20且不存在的Id值,這里使用Id = 15,查詢成功

?  

  以上測(cè)試可以說(shuō)明,一個(gè)Key類(lèi)型的Range鎖,都對(duì)應(yīng)一個(gè)范圍,加鎖的時(shí)候鎖定的是一個(gè)范圍,對(duì)于鎖定范區(qū)間的值,不管是否存在,都是會(huì)被阻塞的,而不僅僅是鎖定已有數(shù)據(jù)行的作用。

  

3,非唯一索引情況下,范圍鎖鎖定的范圍分析

   ? 那么,一個(gè)Key類(lèi)型的Range鎖究竟鎖定的范圍是多大?
    這也是一個(gè)非常有意思的問(wèn)題,這里同樣先給出結(jié)論,分為以下幾種情況:

?

   3.1 如果鎖定的目標(biāo)Id的值存在與表中,且大于表中的最大值,小于表中的最小值,那么鎖定的區(qū)間就是小于鎖定目標(biāo)的第一個(gè)最大值,大于鎖定目標(biāo)的第一個(gè)最小值這個(gè)區(qū)間。

 上述測(cè)試已經(jīng)說(shuō)明了這個(gè)鎖的區(qū)間
 比如上述測(cè)試鎖定的目標(biāo)值,在Session1中以xlock的方式鎖定Id =30,產(chǎn)生的范圍鎖,鎖定的范圍是下限值是20(小于30的最大值),上限值是40(大于30的最小值)
 文字說(shuō)起來(lái)有點(diǎn)繞,畫(huà)個(gè)圖看起來(lái)就直觀了,如下
 鎖定的目標(biāo)是30,因?yàn)樵阪i定30的時(shí)候會(huì)產(chǎn)生范圍鎖,這個(gè)范圍鎖鎖定的區(qū)間是20~40

   

  3.2 如果鎖定的目標(biāo)Id的值不存在與表中,且大于表中的最大值,小于表中的最小值,那么鎖定的區(qū)間就是小于鎖定目標(biāo)的第一個(gè)最大值,大于鎖定目標(biāo)的第一個(gè)最小值這個(gè)區(qū)間。

?  重新開(kāi)始測(cè)試,Session1和Session2中都回滾之前的測(cè)試
  在Session1中執(zhí)行一個(gè)Id = 35的查詢,這個(gè)查詢是添加了排它鎖的方式執(zhí)行的,這個(gè)Id是不存在的。

  

  在Session2中觀察產(chǎn)生的鎖,會(huì)發(fā)現(xiàn)有一個(gè)resource_description是199f61d4d268的范圍鎖?。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

  

  KeyHashValue為199f61d4d268的Id是40,結(jié)合上述列表,40這個(gè)Id對(duì)應(yīng)的鎖的范圍是30~40

  

?

  那么究竟鎖定的范圍是不是30~40,同樣可以在Session2中用共享鎖查詢的方式來(lái)探測(cè)Session1中鎖定的范圍
  測(cè)試1,查詢Id = 31的值,被鎖定

  

  測(cè)試2,查詢Id=39的值,被鎖定

  

  測(cè)試3,查詢Id = 29得值,位于鎖定區(qū)間之外,查詢成功,盡管這是一個(gè)不存在的值,但是在鎖定區(qū)間之外,可以查詢成功。

  測(cè)試4,查詢Id = 50的值,位于鎖定區(qū)間之外,查詢成功,這是一個(gè)存在的Id值

  

  當(dāng)鎖定的目標(biāo)在表中不存在的時(shí)候,且鎖定目標(biāo)大于表中已存在的最小Id值,小于最大Id值,
  那么鎖定的區(qū)間就是小于鎖定目標(biāo)的第一個(gè)最大值,大于鎖定目標(biāo)的第一個(gè)最小值這個(gè)區(qū)間。
  同理,當(dāng)產(chǎn)生范圍鎖的時(shí)候,鎖定的是一個(gè)區(qū)間,而不管這個(gè)區(qū)間是否存在值,或者存在多少個(gè)值。
  同樣用一個(gè)圖來(lái)表示,看起來(lái)更直觀一點(diǎn)

  

?

  3.3 如果鎖定的目標(biāo)Id的值不存在與表中,且大于表中的最大值 ,鎖定的范圍是一個(gè)表中最大值到無(wú)窮大的一個(gè)范圍

?  重新開(kāi)始測(cè)試,Session1和Session2中都回滾之前的測(cè)試
  在Session1中執(zhí)行一個(gè)Id = 60的查詢,這個(gè)查詢是添加了排它鎖的方式執(zhí)行的,這個(gè)Id是不存在的

?  

  在Session2中觀察產(chǎn)生的范圍鎖,這一次發(fā)現(xiàn)resource_description是一個(gè)(ffffffffffff),可以認(rèn)為(ffffffffffff)這個(gè)KeyHashValue是一個(gè)無(wú)窮大的值

  

  那么問(wèn)題就來(lái)了,鎖定范圍的上限是一個(gè)無(wú)窮大的值,那么下限在哪里?
  同樣,可以在Session2中采用共享鎖探測(cè)的方式來(lái)觀察Session1鎖定的范圍
  測(cè)試1,在Session2中查詢Id = 70的值,Id = 70是大于表中的一個(gè)最大值,被鎖定(鎖定范圍上限為無(wú)窮大,同理更大值也能被鎖定)

  

  測(cè)試1,在Session2中查詢Id = 50的值,Id = 50是表中的一個(gè)最大值,被鎖定

  

  測(cè)試3,在Session2中查詢Id = 49的值,Id = 49是小于表中的一個(gè)最大值,未被鎖定,盡管這個(gè)值不存在

?  

  測(cè)試4,在Session2中查詢Id = 40的值,Id = 40是小于表中的一個(gè)最大值且存在的值,未被鎖定

?  

  當(dāng)鎖定的目標(biāo)在表中不存在的時(shí)候,且鎖定目標(biāo)大于表中已存在的最大Id值,那么鎖定的區(qū)間就是從表中最大值開(kāi)始到無(wú)窮大的一個(gè)區(qū)間。
  同樣用一個(gè)圖來(lái)表示,看起來(lái)更直觀一點(diǎn)

?  

?

4,關(guān)于索引是否唯一與鎖定期間臨界值的關(guān)系

  ?上文測(cè)試過(guò)程中,給出的Key與其對(duì)應(yīng)的范圍鎖的鎖定關(guān)系中如下,鎖定范圍是包含了臨界值的(雙閉區(qū)間),但是一直沒(méi)有刻意測(cè)試臨界值。

  


  沒(méi)有刻意測(cè)試臨界值是因?yàn)榕R界值是否被鎖定,是跟索引的唯一性有關(guān),如果索引時(shí)非唯一的,對(duì)應(yīng)的范圍鎖在鎖定的時(shí)候就包含臨界值,如果索引唯一,情況是不一樣的。
  下文中會(huì)有說(shuō)明。

  對(duì)于唯一索引,分為以下幾種情況:

?

?  4.1 唯一索引情況下,鎖定目標(biāo)為已存在的Id值,且Id值大于表中的最小Id,小于表中的最大Id

  在索引唯一的情況下,鎖定目標(biāo)是一個(gè)表中已存在的Id值,那么究竟是不是范圍鎖?
  很多人認(rèn)為如果鎖定目標(biāo)是已存在的唯一索引,沒(méi)有產(chǎn)生Range鎖的時(shí)候就沒(méi)有“范圍鎖”的概念了,其實(shí)是不對(duì)的。
  繼續(xù)測(cè)試,回滾Session1,Session2,刪除表中一開(kāi)始創(chuàng)建的非唯一索引,Id上創(chuàng)建成一個(gè)唯一的聚集索引。

  

  測(cè)試在觀察數(shù)據(jù)的索引頁(yè),發(fā)生了變化(重建了聚集索引,數(shù)據(jù)頁(yè)發(fā)生了變化,想一想為什么?)

  

  用同樣的方式得到數(shù)據(jù)的KeyHashValue與數(shù)據(jù)行的對(duì)應(yīng)關(guān)系如下

  10:d08358b1108f
  20:286fc18d83ea
  30:8034b699f2c9
  40:d8b6f3f4a521
  50:f84b73ce9e8d

  同理在Session1中查詢一個(gè)已存在的Id值,作為鎖定目標(biāo)

  

  在Session2中觀察產(chǎn)生的鎖,鎖定的行是很明顯是Id = 30的數(shù)據(jù)行,但是是一個(gè)X鎖,而非范圍鎖(RangeX-X)。

  那么此時(shí),僅僅是會(huì)鎖定當(dāng)前行嗎?

  

?  ? 測(cè)試1,在Session2中查詢一個(gè)小于輸定目標(biāo)(但是大于20,因?yàn)?0是小于鎖定目標(biāo)的已存在的最大值)的值,發(fā)現(xiàn)依舊是被鎖定,

? ?  

  測(cè)試2,再測(cè)一個(gè)Id =29的值,一樣是被鎖定的

  

  這里捎帶看一下Session2(Sess_id = 55)被Session1(Session_id = 54)的阻塞情況
  這里的wait_type為L(zhǎng)CK_M_RS_S,LCK_M_RS_S是啥鎖?LCK_M_RS_S:等待獲取當(dāng)前鍵值上的共享鎖以及當(dāng)前鍵和上一個(gè)鍵之間的共享范圍鎖
  依舊是是“當(dāng)前鍵和上一個(gè)鍵之間的共享范圍鎖”啊,依舊是范圍鎖啊,因此說(shuō),鎖定已存在與表中的唯一索引的時(shí)候,雖然沒(méi)有變現(xiàn)出來(lái)范圍鎖(sys.dm_tran_locks),但是本質(zhì)上仍然是范圍鎖。

  

  測(cè)試3,測(cè)試一個(gè)小于鎖定目標(biāo),且存在與表中的最大值(也就是20),發(fā)現(xiàn)未被鎖定(這就是唯一索引與非唯一索引在臨界值上的鎖定區(qū)別,如果是非唯一索引,這個(gè)20的臨界值將會(huì)被鎖定)

  

  測(cè)試4,測(cè)試一個(gè)大于鎖定區(qū)間的值,也即如下的Id = 31,查詢是成功的,即便是Id= 31不存在的。

?

?  從中可以發(fā)現(xiàn),在唯一索引的情況下,

  如果鎖定的目標(biāo)Id的值存在與表中,且大于表中的最大值,小于表中的最小值,那么鎖定的區(qū)間就是當(dāng)前值到小于鎖定目標(biāo)的第一個(gè)最大值

  具實(shí)際例子來(lái)說(shuō)就是,鎖定目標(biāo)是30的情況下,鎖定的區(qū)間值是(20,30]

?  

?

?  4.2 唯一索引情況下,鎖定目標(biāo)為不存在的Id值,且Id值大于表中的最小Id,小于表中的最大Id

  這種情況就不一一截圖了,結(jié)論如同非唯一索引,比如鎖定目標(biāo)為Id = 35的情況下,鎖的范圍是(30,40],也即左開(kāi)(區(qū)間)右閉(區(qū)間)

  

  4.3 唯一索引情況下,鎖定目標(biāo)為不存在的Id值,且Id值大于表中的最大Id?

  這種情況也就不一一截圖了,結(jié)論如同非唯一索引,比如鎖定目標(biāo)為Id = 60的情況下,鎖的范圍是(50,+∞),也即左開(kāi)(區(qū)間)

?

5,關(guān)于查詢條件是一個(gè)區(qū)間值的情況

  因?yàn)橹懒藛蝹€(gè)值查詢的鎖的區(qū)間,對(duì)于范圍查詢的情況,無(wú)非就是將查詢范圍進(jìn)行分解,分解出單個(gè)值鎖定的范圍,然后將這個(gè)區(qū)間進(jìn)行合并得到一個(gè)區(qū)間的并集。
  有興趣的可以自行測(cè)試。

  

6,關(guān)于查詢條件是一個(gè)非聚集索引的情況

  上述都是以聚集索引為查詢條件進(jìn)行測(cè)試的,如果是非聚集索引情況雷同,只不過(guò)是多了非聚集索引一級(jí)的鎖,有時(shí)間再測(cè)試。

?

總結(jié):

  序列化隔離級(jí)別下會(huì)阻止幻讀的產(chǎn)生,幻讀的產(chǎn)生是通過(guò)范圍鎖鎖定的是一個(gè)范圍來(lái)實(shí)現(xiàn)的,
  Range 鎖最主要的是鎖定一個(gè)范圍,鎖定的不僅僅是表中已有的數(shù)據(jù),而是一個(gè)區(qū)間,而不管這個(gè)范圍之內(nèi)是否存在數(shù)據(jù),
  任何Session試圖操作被其他Session范圍鎖鎖定的數(shù)據(jù),不管在表中是否存在,都將被阻塞,直到產(chǎn)生范圍鎖的Session事物提交。

  此時(shí)也不難理解,對(duì)于那個(gè)最經(jīng)典的問(wèn)題:并發(fā)情況下,存在則更新,不存在則插入,不管采用什么寫(xiě)法,
  比如并發(fā)插入,任何一個(gè)Session執(zhí)行之前,都先鎖定一個(gè)范圍,即便是這個(gè)值不存在,
  等到相同的值進(jìn)來(lái)的時(shí)候,同樣需要鎖定一個(gè)范圍,那么此時(shí)是會(huì)被阻塞的,因此可以實(shí)現(xiàn)并發(fā)存在則更新,不存在則插入的效果
  了解了Range鎖的鎖定原理,也不會(huì)糾結(jié)不同寫(xiě)法的區(qū)別了,目的都是加Range鎖,鎖定范圍,防止并發(fā)情況下的幻讀出現(xiàn)。 

  以上純屬個(gè)人測(cè)試和簡(jiǎn)單的推斷,難免存在錯(cuò)誤的地方,如有興趣,歡迎探討指正,謝謝。

?

最后
  其實(shí)樓主是看了MySQL的gap鎖、next-key鎖之后回頭來(lái)看SQL Server中的Range鎖的,
  最終發(fā)現(xiàn),除了一些細(xì)節(jié),鎖的實(shí)現(xiàn)在套路上都是一樣的,比如對(duì)待幻讀的處理上,可謂是在“道”的層面上都是一個(gè)原則。
  一個(gè)叫做Range范圍鎖,一個(gè)叫做gap鎖、next-key鎖,不同的表現(xiàn)形式只是“術(shù)”上的問(wèn)題罷了。
?

?

?太累了,眼睛脖子都受不鳥(niǎo)了。

?

參考資料,各種翻書(shū),各種上網(wǎng)查。

?

?

?

轉(zhuǎn)載于:https://www.cnblogs.com/wy123/p/7501261.html

《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的浅析SQL Server在可序列化隔离级别下,防止幻读的范围锁的锁定问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。