您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)數(shù)據(jù)庫(kù)需要鎖機(jī)制的原因以及鎖機(jī)制的種類是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
為什么要鎖
數(shù)據(jù)庫(kù)是一個(gè)多用戶使用的共享資源,比如一個(gè)用戶表t_user,兩個(gè)瀏覽器前面的人登錄了同個(gè)一個(gè)賬號(hào),把電話號(hào)碼改了。當(dāng)多個(gè)用戶并發(fā)地存取數(shù)據(jù)時(shí),在數(shù)據(jù)庫(kù)中就會(huì)產(chǎn)生多個(gè)事務(wù)同時(shí)存取同一數(shù)據(jù)的情況。若對(duì)并發(fā)操作不加控制就可能會(huì)讀取和存儲(chǔ)不正確的數(shù)據(jù),破壞數(shù)據(jù)庫(kù)的一致性(臟讀,不可重復(fù)讀,幻讀等),可能產(chǎn)生死鎖。為了解決這個(gè)問(wèn)題,加鎖是一個(gè)非常重要的技術(shù),對(duì)實(shí)現(xiàn)數(shù)據(jù)庫(kù)并發(fā)控制是一個(gè)好的方案。簡(jiǎn)單說(shuō),當(dāng)一個(gè)執(zhí)行sql語(yǔ)句的事務(wù)想要操作表記錄之前,先向數(shù)據(jù)庫(kù)發(fā)出請(qǐng)求,對(duì)你訪問(wèn)的記錄集加鎖,在這個(gè)事務(wù)釋放這個(gè)鎖之前,其他事務(wù)不能對(duì)這些數(shù)據(jù)進(jìn)行更新操作。
有哪些鎖
鎖包括行級(jí)鎖、表級(jí)鎖、悲觀鎖、樂(lè)觀鎖
1. 行級(jí)鎖:一種它鎖,防止另外事務(wù)修改此行;
在使用以下語(yǔ)句時(shí),Oracle會(huì)自動(dòng)應(yīng)用行級(jí)鎖:
INSERT、UPDATE、DELETE、SELECT … FOR UPDATE [OF columns] [WAIT n | NOWAIT];SELECT … FOR UPDATE語(yǔ)句,允許用戶一次鎖定多條記錄進(jìn)行更新.
使用commit或者rollback釋放鎖。
MySql的innodb存儲(chǔ)引擎默認(rèn)是行級(jí)鎖。特點(diǎn):開鎖大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。適合于有大量按索引更新少量不同數(shù)據(jù),同時(shí)又有并發(fā)查詢的應(yīng)用,如一些在線事務(wù)處理系統(tǒng)。
2.表級(jí)鎖:5種
1)行共享 (ROW SHARE) – 禁止排他鎖定表,與行排他類似,區(qū)別是別的事務(wù)還可以在此表上加任何排他鎖。(除排他(exclusive)外)
2)行排他(ROW EXCLUSIVE) – 禁止使用排他鎖和共享鎖,其他事務(wù)依然可以并發(fā)地對(duì)相同數(shù)據(jù)表執(zhí)行查詢,插入,更新,刪除操作,或?qū)Ρ韮?nèi)數(shù)據(jù)行加鎖的操作,但不能有其他的排他鎖(自身是可以的,沒(méi)發(fā)現(xiàn)有什么用)
3)共享鎖(SHARE) - 鎖定表,對(duì)記錄只讀不寫,多個(gè)用戶可以同時(shí)在同一個(gè)表上應(yīng)用此鎖,在表沒(méi)有被任何DML操作時(shí),多個(gè)事務(wù)都可加鎖,但只有在僅一個(gè)事務(wù)加鎖的情況下只有此事務(wù)才能對(duì)表更新;當(dāng)表已經(jīng)被更新或者指定要更新時(shí)(select for update),任何事務(wù)都不能加此鎖了。
4)共享行排他(SHARE ROW EXCLUSIVE) – 比共享鎖更多的限制,禁止使用共享鎖及更高的鎖,在表沒(méi)有被任何DML操作時(shí),只有一個(gè)事務(wù)可以加鎖,可以更新,書上說(shuō)別的事務(wù)可以使用select for update鎖定選中的數(shù)據(jù)行,可是實(shí)驗(yàn)后沒(méi)被驗(yàn)證。
5)排他(EXCLUSIVE) – 限制最強(qiáng)的表鎖,僅允許其他用戶查詢?cè)摫淼男?。禁止修改和鎖定表
行級(jí)鎖和表級(jí)鎖是根據(jù)鎖的粒度來(lái)區(qū)分的,行記錄,表都是資源,鎖是作用在這些資源上的。如果粒度比較小(比如行級(jí)鎖),可以增加系統(tǒng)的并發(fā)量但需要較大的系統(tǒng)開銷,會(huì)影響到性能,出現(xiàn)死鎖,,因?yàn)榱6刃t操作的鎖的數(shù)量會(huì)增加;如果作用在表上,粒度大,開銷小,維護(hù)的鎖少,不會(huì)出現(xiàn)死鎖,但是并發(fā)是相當(dāng)昂貴的,因?yàn)殒i定了整個(gè)表就限制了其它事務(wù)對(duì)這個(gè)表中其他記錄的訪問(wèn)。
悲觀鎖:
Pessimistic Lock正如其名,它指的是對(duì)數(shù)據(jù)被外界(包括本系統(tǒng)當(dāng)前的其他事務(wù),以及來(lái)自外部系統(tǒng)的事務(wù)處理)修改持保守悲觀態(tài)度,事務(wù)每次去操作數(shù)據(jù)的時(shí)候都假設(shè)有其他事務(wù)會(huì)修改需要訪問(wèn)的數(shù)據(jù),所以在訪問(wèn)之前都要求上鎖,行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖,因此,在整個(gè)數(shù)據(jù)處理過(guò)程中,將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實(shí)現(xiàn),往往依靠數(shù)據(jù)庫(kù)提供的鎖機(jī)制(也只有數(shù)據(jù)庫(kù)層提供的鎖機(jī)制才能 真正保證數(shù)據(jù)訪問(wèn)的排他性,否則,即使在本系統(tǒng)中實(shí)現(xiàn)了加鎖機(jī)制,也無(wú)法保證外部系 統(tǒng)不會(huì)修改數(shù)據(jù))。
一個(gè)典型的倚賴數(shù)據(jù)庫(kù)的悲觀鎖調(diào)用: select * from account where name=”Erica” for update 這條sql 語(yǔ)句鎖定了account 表中所有符合檢索條件(name=”Erica”)的記錄。 本次事務(wù)提交之前(事務(wù)提交時(shí)會(huì)釋放事務(wù)過(guò)程中的鎖),外界無(wú)法修改這些記錄。
Hibernate悲觀鎖實(shí)現(xiàn):基于數(shù)據(jù)庫(kù)鎖機(jī)制
Query q=Session.createQuery("select * from t_profit where amount>10000");
q.setLockMode("Profit",LockMode.UPGRADE);//Profit是Profit類的別名
List<Profit> ps=q.list();
執(zhí)行的sql:select ....from t_profit where amount>10000 for update. hibernate的悲觀鎖通過(guò)數(shù)據(jù)庫(kù)的for update實(shí)現(xiàn)。
LockMode.NONE:無(wú)鎖機(jī)制;
LockMode.WRITE:insert,update記錄時(shí)自動(dòng)獲取悲觀鎖;
LockMode.READ在讀取時(shí)自動(dòng)獲取悲觀鎖;
LockMode.UPGRADE:利用數(shù)據(jù)庫(kù)的for update子句加鎖;
LockMode.UPGRADE_NOWAIT:oracle特定實(shí)現(xiàn),用oracle的for update nowait子句加鎖
樂(lè)觀鎖:
Optimistic Lock,和悲歡鎖相反,事務(wù)每次去操作數(shù)據(jù)之前,都假設(shè)其他事務(wù)不會(huì)修改這些需要訪問(wèn)的數(shù)據(jù) ,所以 在訪問(wèn)之前不要求上鎖,只是在進(jìn)行更新修改操作的時(shí)候判斷一下在訪問(wèn)的期間有沒(méi)有其他人修改數(shù)據(jù) 了。它適用于多讀的應(yīng)用類型,沖突真的發(fā)生比較少的時(shí)候就比較好,這樣省去了開銷的開銷,可以提高吞吐量;但如果是真的經(jīng)常要發(fā)生沖突的,那每次還要去判斷進(jìn)行retry,反倒降低的性能,這個(gè)時(shí)候悲歡鎖比較好。數(shù)據(jù)庫(kù)如果提供類似于write_condition機(jī)制的其實(shí)都是提供的樂(lè)觀鎖。
它的實(shí)現(xiàn)大多是基于數(shù)據(jù)版本versin記錄機(jī)制。舉個(gè)例子:
1.利潤(rùn)表t_profit中有一個(gè) version字段,當(dāng)前值為1;而總資產(chǎn)余額字段(balance)為$10000
2.操作員A讀出version=1,從總資產(chǎn)減除2000,10000-2000=8000.
3.A還沒(méi)操作結(jié)束,此時(shí)操作員B也讀出version=1,總資產(chǎn)減除5000,10000-5000=5000.
4.A操作完成,把version加1,修改為2,把總資產(chǎn)減2000后提交更新數(shù)據(jù)庫(kù),更新成功
5.B操作了,也加version加1,修改為2,把總資產(chǎn)減5000后提交更新數(shù)據(jù)庫(kù),此時(shí)發(fā)現(xiàn)version已經(jīng)為2了,如B修改后加1的version一樣,不滿足樂(lè)觀鎖策略:"提交的版本必有大于記錄當(dāng)前的版本才能執(zhí)行"。因此B的操作請(qǐng)求被駁回,這樣就避免了B就version=1的舊數(shù)據(jù)修改的結(jié)果覆蓋了A操作的結(jié)果的可能。如沒(méi)有樂(lè)觀鎖,那A減去2000后剩余8000,但B操作的時(shí)候是用10000-5000剩余5000的,如果B的提交成功,總資產(chǎn)余額就是5000,但實(shí)際情況應(yīng)該是8000-5000=3000的。出現(xiàn)總資產(chǎn)表記錄和實(shí)際支出不一致。
Hibernate對(duì)樂(lè)觀鎖的實(shí)現(xiàn):
<hibernate-mapping>
<class name="com.f.TProfit" table="t_profit" optimistic-lock="version"></class>
</hibernate-mapping>
關(guān)于數(shù)據(jù)庫(kù)需要鎖機(jī)制的原因以及鎖機(jī)制的種類是什么就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。