Oracle锁机制的总结【转】
??最近在研究Oracle鎖機(jī)制的時(shí)候發(fā)現(xiàn)網(wǎng)上的資料魚龍混雜將,很多將問題復(fù)雜化,讓人感覺沒有條理性。經(jīng)過查詢?cè)祭碚撡Y料,總結(jié)如下:
???????? 在數(shù)據(jù)庫理論中,我們知道。我們?cè)趫?zhí)行并發(fā)訪問數(shù)據(jù)庫表時(shí),如果沒有任何一致性控制措施,那么會(huì)出現(xiàn)以下幾種數(shù)據(jù)不一致的情況:1)提交被覆蓋;2)不可重復(fù)讀(其中包括了幻讀);3)讀“臟數(shù)據(jù)”。經(jīng)過仔細(xì)分析,發(fā)現(xiàn)引起這些情況的根本原因是:在對(duì)數(shù)據(jù)庫公共資源訪問時(shí),出現(xiàn)了事務(wù)交叉的情況。因此,在數(shù)據(jù)庫的理論里有“可串行化”這種衡量標(biāo)準(zhǔn),就是說:如果我們?cè)诓l(fā)情況下通過對(duì)并發(fā)事務(wù)的控制得到的最終結(jié)果和我們按順序一個(gè)個(gè)執(zhí)行事務(wù)是一樣的結(jié)果,那么我們就認(rèn)為這種控制是“可串行化”的,是正確的。
????????? 鎖機(jī)制是當(dāng)前解決這些問題的最有效的辦法,以下的兩個(gè)概念“基本鎖”和“意向鎖”是最基本的兩個(gè)概念,是構(gòu)成所有其他鎖的基礎(chǔ)。
????????? 1)為了在并發(fā)性和一致性這對(duì)矛盾中合理取舍,提供了兩種最基本的鎖:共享鎖(讀鎖)、排它鎖(寫鎖)。
?????????共享鎖(S):如果事務(wù)T對(duì)表A加上共享鎖,則事務(wù)T可以讀該表,但是不能修改該表數(shù)據(jù)。其他事務(wù)也只能對(duì)該對(duì)象加上共享鎖,但是不能加上排他鎖。這就保證了其他事務(wù)可以讀A表數(shù)據(jù),但是不能修改A表數(shù)據(jù)(這就不會(huì)影響到讀該表的事務(wù)了,有利于并發(fā)操作)。
???????? 排他鎖(X):如果事務(wù)T對(duì)對(duì)象A加上排他鎖,則只允許T對(duì)A對(duì)象讀取和修改,其他事務(wù)不能對(duì)A增加任何鎖,只到T釋放加載A上的排他鎖。
???????? 那么如何使用這些鎖解決問題呢?數(shù)據(jù)庫的基本理論提出了三種級(jí)別的封鎖協(xié)議,封的越高,控制的范圍越大,一致性也越好,并發(fā)性也越差。具體的大家可以查資料,也很簡(jiǎn)單,這里為了節(jié)約篇幅不再敘述。
????????? 2)可是動(dòng)輒就給整個(gè)表加鎖,這有點(diǎn)魯莽草率。我們知道,在一個(gè)并發(fā)的環(huán)境下,我們的程序(事務(wù))操作的常常并不是表中的同一樣數(shù)據(jù),而這樣大范圍的控制表數(shù)據(jù)很顯然不利于并發(fā),那么我們可以針對(duì)需要縮小控制范圍,于是提出了“多粒度封鎖”的概念。也就是說,程序(事務(wù))既可以封鎖整個(gè)表,也可以只封鎖某些和我們有關(guān)的行,這樣就不會(huì)影響其他程序(事務(wù))到該表中其他的行。可是新的問題又來了,我們?nèi)绻獙?duì)某個(gè)表進(jìn)行某種操作,比如刪除整個(gè)表的數(shù)據(jù),那么數(shù)據(jù)庫程序就要遍歷整個(gè)表的每個(gè)行,這很顯然過于消耗資源,那咋辦?于是,“意向鎖”應(yīng)運(yùn)而生。意向鎖的概念基本上是這個(gè)意思:如果我們要封鎖表的某個(gè)行,則也在該行所在的表上加上鎖。這樣的話在對(duì)整個(gè)表進(jìn)行操作時(shí),就不用遍歷表里的所有行了。通過和前邊提到的共享鎖和排他鎖,我們組合出三種鎖:
?????????? 意向共享鎖(IS):如果我們對(duì)表加IS鎖,表示該表中的某個(gè)行被加上了S鎖。
?????????? 意向排他鎖(IX):如果我們對(duì)表加IX鎖,表時(shí)該表中的某個(gè)行上被加上X鎖。
?????????? 共享意向排他鎖(ISX)。表示先對(duì)某個(gè)表加上S鎖,然后再加上X鎖,表示要讀取整個(gè)表的數(shù)據(jù),但是只對(duì)其中的一部分行做修改。
????????那么最終一共得到5種鎖:共享鎖(S)、排他鎖(T)、意向共享鎖(IS)、意向排他鎖(IX)、共享意向排他鎖(SIX)。
??????? 好,談完理論,我們和具體的數(shù)據(jù)庫Oracle結(jié)合起來,Oracle一共提供了共享鎖(S)、排他鎖(T)、行級(jí)共享鎖(RS)、行級(jí)排他鎖(RX)、共享行級(jí)排他鎖(SRX)。和上一句話一對(duì)比,我們就知道了,它們是一一對(duì)應(yīng)的。可是,Oracle作為一個(gè)成功的數(shù)據(jù)庫,總是有自己別出心裁的地方。可能Oracle認(rèn)為讀數(shù)據(jù)的時(shí)候加鎖這種機(jī)制,在很大程度上是浪費(fèi),比如用戶修改的數(shù)據(jù)大多數(shù)是自己的不會(huì)影響到別的用戶(只局限于某些行,不會(huì)影響其他行)。所以,默認(rèn)情況下,Oracle在讀取表中數(shù)據(jù)的時(shí)候并沒有加鎖,而是采用了回滾段的策略解決了這個(gè)問題,具體的原理在稍后再說。這樣的確是提高了并發(fā)性,但是我認(rèn)為,這其實(shí)也是種冒險(xiǎn)行為,一旦出現(xiàn)用戶B必須要讀取用戶A的數(shù)據(jù),而且要參考讀取的結(jié)果進(jìn)行一些重要的操作時(shí),這個(gè)時(shí)候就需要我們自己手動(dòng)去加鎖了(Oracle的確提供了這種功能,讓我們自己用語句去加鎖)。下邊,我們?cè)敿?xì)談下Oracle自己鎖的具體行為:
??????? 共享鎖:通過lock table in share mode命令添加該S鎖。在該鎖定模式下,不允許任何用戶更新表。但是允許其他用戶發(fā)出select …from for update命令對(duì)表添加RS鎖。
??????? 排他鎖:通過lock table in exclusive mode命令添加X鎖。在該鎖定模式下,其他用戶不能對(duì)表進(jìn)行任何的DML和DDL操作,該表上只能進(jìn)行查詢。
??????? 行級(jí)共享鎖:通常是通過select … from for update語句添加的,同時(shí)該方法也是我們用來手工鎖定某些記錄的主要方法。比如,當(dāng)我們?cè)诓樵兡承┯涗浀倪^程中,不希望其他用戶對(duì)查詢的記錄進(jìn)行更新操作,則可以發(fā)出這樣的語句。當(dāng)數(shù)據(jù)使用完畢以后,直接發(fā)出rollback命令將鎖定解除。當(dāng)表上添加了RS鎖定以后,不允許其他事務(wù)對(duì)相同的表添加排他鎖,但是允許其他的事務(wù)通過DML語句或lock命令鎖定相同表里的其他數(shù)據(jù)行。
?????? 行級(jí)排他鎖:當(dāng)我們進(jìn)行DML時(shí)會(huì)自動(dòng)在被更新的表上添加RX鎖,或者也可以通過執(zhí)行l(wèi)ock命令顯式的在表上添加RX鎖。在該鎖定模式下,允許其他的事務(wù)通過DML語句修改相同表里的其他數(shù)據(jù)行,或通過lock命令對(duì)相同表添加RX鎖定,但是不允許其他事務(wù)對(duì)相同的表添加排他鎖(X鎖)。
?????? 共享行級(jí)排他鎖:通過lock table in share row exclusive mode命令添加SRX鎖。該鎖定模式比行級(jí)排他鎖和共享鎖的級(jí)別都要高,這時(shí)不能對(duì)相同的表進(jìn)行DML操作,也不能添加共享鎖。
??????? 好了,引用別人的一個(gè)例子來描述Oracle如何通過回滾段來解決重復(fù)讀和幻讀的問題:
??????? 如果有一個(gè)事務(wù)A執(zhí)行以下語句:update employees set last_name='HanSijie'? where employee_id=100;如果當(dāng)前有一個(gè)用戶(假設(shè)為B)發(fā)出SQL語句,檢索employee_id為100的記錄信息,這時(shí)服務(wù)器進(jìn)程發(fā)現(xiàn)被檢索的記錄有鎖定標(biāo)記,說明當(dāng)前該記錄已經(jīng)被其他用戶修改了,但是還沒提交。于是根據(jù)數(shù)據(jù)行頭部記錄的ITL槽的槽號(hào),在數(shù)據(jù)塊頭部找到該ITL槽,并根據(jù)其中記錄的undo數(shù)據(jù)塊的地址,找到該undo 數(shù)據(jù)塊,將其中所保存的改變前的舊值取出,并據(jù)此構(gòu)建CR(Consistent Read一致性讀)塊,該CR塊中的數(shù)據(jù)就是被更新的數(shù)據(jù)塊(也就是58號(hào)數(shù)據(jù)塊)在更新前的內(nèi)容。于是根據(jù)該CR塊的內(nèi)容,將用戶所需要的信息返回給C。
??????? 以上的例子,可以證明之前我所說的擔(dān)心的地方,也就是說,假如我們這個(gè)用戶B要參照這個(gè)數(shù)據(jù)來決定下一步程序重要的走向,那么我們?cè)谧鲞@件事情的時(shí)候,必須也要對(duì)該記錄加鎖,因?yàn)镺racle并沒有對(duì)我們的讀取采取加鎖的行為。我們必須要控制我們?cè)谧鱿乱徊絼?dòng)作前的這個(gè)“決定因素”不能被別人修改。
??????? 另外,還有一點(diǎn)總結(jié),由于我沒有深入研究過多線程編程,只是在研究Struts2時(shí),對(duì)Struts2處理Action的多線程問題時(shí)研究了下ThreadLocal模式。得出以下總結(jié),可能不完善。個(gè)人認(rèn)為,資源分為兩種,一種是:多個(gè)線程必須交互的資源,比如表中的數(shù)據(jù),再比如必須參考的某個(gè)成員變量。還有一種是:多線程可以不用交互的資源,比如我們Struts2中的成員變量。第一種情況,相當(dāng)于是個(gè)十字路口,在不允許“修天橋”的情況下,多個(gè)線程必須要走這個(gè)交叉點(diǎn)。第二種情況是,可以通過“修天橋”來避免在同一個(gè)空間里的沖突。ThreadLocal就是基于這種思想,是為了降低線程沖突,也是為了節(jié)約資源等待的時(shí)間,本質(zhì)上是計(jì)算機(jī)中的真理“空間換時(shí)間”。
??????? 以上內(nèi)容有很多借鑒了數(shù)據(jù)庫基本理論,但是將抽象的對(duì)象具體到表和表中的行,這樣有助于理解。主要是為了澄清一些概念,比如有人將“幻讀”單獨(dú)作為一種不一致情況,而省去了“提交被覆蓋”這種情況。我個(gè)人認(rèn)為,很顯然,幻讀只是不可重復(fù)讀的一種情況(幻讀強(qiáng)調(diào)的是集合)。中間也摘錄了其他人文章中的部分內(nèi)容。如果中間有錯(cuò)誤,希望留言評(píng)論。
轉(zhuǎn)載于:https://www.cnblogs.com/hsz1124/p/7409981.html
總結(jié)
以上是生活随笔為你收集整理的Oracle锁机制的总结【转】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Boot系列教程一:Ecl
- 下一篇: perl6正则 4: before /