Oracle數(shù)據(jù)庫的鎖類型
專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)安陽免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了上千企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
根據(jù)保護(hù)的對象不同,Oracle數(shù)據(jù)庫鎖可以分為以下幾大類:DML鎖(data locks,數(shù)據(jù)鎖),用于保護(hù)數(shù)據(jù)的完整性;DDL鎖(dictionary locks,字典鎖),用于保護(hù)數(shù)據(jù)庫對象的結(jié)構(gòu),如表、索引等的結(jié)構(gòu)定義;內(nèi)部鎖和閂(internal locks and latches),保護(hù)數(shù)據(jù)庫的內(nèi)部結(jié)構(gòu)。
DML鎖的目的在于保證并發(fā)情況下的數(shù)據(jù)完整性,本文主要討論DML鎖。在Oracle數(shù)據(jù)庫中,DML鎖主要包括TM鎖和TX鎖,其中TM鎖稱為表級鎖,TX鎖稱為事務(wù)鎖或行級鎖。
當(dāng)Oracle執(zhí)行DML語句時,系統(tǒng)自動在所要操作的表上申請TM類型的鎖。當(dāng)TM鎖獲得后,系統(tǒng)再自動申請TX類型的鎖,并將實(shí)際鎖定的數(shù)據(jù)行的鎖標(biāo)志位進(jìn)行置位。這樣在事務(wù)加鎖前檢查TX鎖相容性時就不用再逐行檢查鎖標(biāo)志,而只需檢查TM鎖模式的相容性即可,大大提高了系統(tǒng)的效率。TM鎖包括了SS、SX、S、X等多種模式,在數(shù)據(jù)庫中用0-6來表示。不同的SQL操作產(chǎn)生不同類型的TM鎖。如表1所示。
在數(shù)據(jù)行上只有X鎖(排他鎖)。在 Oracle數(shù)據(jù)庫中,當(dāng)一個事務(wù)首次發(fā)起一個DML語句時就獲得一個TX鎖,該鎖保持到事務(wù)被提交或回滾。當(dāng)兩個或多個會話在表的同一條記錄上執(zhí)行DML語句時,第一個會話在該條記錄上加鎖,其他的會話處于等待狀態(tài)。當(dāng)?shù)谝粋€會話提交后,TX鎖被釋放,其他會話才可以加鎖。
當(dāng)Oracle數(shù)據(jù)庫發(fā)生TX鎖等待時,如果不及時處理常常會引起Oracle數(shù)據(jù)庫掛起,或?qū)е滤梨i的發(fā)生,產(chǎn)生ORA-60的錯誤。這些現(xiàn)象都會對實(shí)際應(yīng)用產(chǎn)生極大的危害,如長時間未響應(yīng),大量事務(wù)失敗等。
TX鎖等待的分析
在介紹了有關(guān)地Oracle數(shù)據(jù)庫鎖的種類后,下面討論如何有效地監(jiān)控和解決鎖等待現(xiàn)象,及在產(chǎn)生死鎖時如何定位死鎖的原因。
監(jiān)控鎖的相關(guān)視圖 數(shù)據(jù)字典是Oracle數(shù)據(jù)庫的重要組成部分,用戶可以通過查詢數(shù)據(jù)字典視圖來獲得數(shù)據(jù)庫的信息。和鎖相關(guān)的數(shù)據(jù)字典視圖如表2所示。
TX鎖等待的監(jiān)控和解決在日常工作中,如果發(fā)現(xiàn)在執(zhí)行某條SQL時數(shù)據(jù)庫長時間沒有響應(yīng),很可能是產(chǎn)生了TX鎖等待的現(xiàn)象。為解決這個問題,首先應(yīng)該找出持鎖的事務(wù),然后再進(jìn)行相關(guān)的處理,如提交事務(wù)或強(qiáng)行中斷事務(wù)。
死鎖的監(jiān)控和解決在數(shù)據(jù)庫中,當(dāng)兩個或多個會話請求同一個資源時會產(chǎn)生死鎖的現(xiàn)象。死鎖的常見類型是行級鎖死鎖和頁級鎖死鎖,Oracle數(shù)據(jù)庫中一般使用行級鎖。下面主要討論行級鎖的死鎖現(xiàn)象。
當(dāng)Oracle檢測到死鎖產(chǎn)生時,中斷并回滾死鎖相關(guān)語句的執(zhí)行,報ORA-00060的錯誤并記錄在數(shù)據(jù)庫的日志文件alertSID.log中。同時在user_dump_dest下產(chǎn)生了一個跟蹤文件,詳細(xì)描述死鎖的相關(guān)信息。
在日常工作中,如果發(fā)現(xiàn)在日志文件中記錄了ora-00060的錯誤信息,則表明產(chǎn)生了死鎖。這時需要找到對應(yīng)的跟蹤文件,根據(jù)跟蹤文件的信息定位產(chǎn)生的原因。
如果查詢結(jié)果表明,死鎖是由于bitmap索引引起的,將IND_T_PRODUCT_HIS_STATE索引改為normal索引后,即可解決死鎖的問題。
表1 Oracle的TM鎖類型
鎖模式 鎖描述 解釋 SQL操作
0 none
1 NULL 空 Select
2 SS(Row-S) 行級共享鎖,其他對象只能查詢這些數(shù)據(jù)行 Select for update、Lock for update、Lock row share
3 SX(Row-X) 行級排它鎖,在提交前不允許做DML操作 Insert、Update、Delete、Lock row share
4 S(Share) 共享鎖 Create index、Lock share
5 SSX(S/Row-X) 共享行級排它鎖 Lock share row exclusive
6 X(Exclusive) 排它鎖 Alter table、Drop able、Drop index、Truncate table 、Lock exclusive
表2 數(shù)據(jù)字典視圖說明
視圖名 描述 主要字段說明
v$session 查詢會話的信息和鎖的信息。 sid,serial#:表示會話信息。
program:表示會話的應(yīng)用程序信息。
row_wait_obj#:表示等待的對象。
和dba_objects中的object_id相對應(yīng)。
v$session_wait 查詢等待的會話信息。 sid:表示持有鎖的會話信息。
Seconds_in_wait:表示等待持續(xù)的時間信息
Event:表示會話等待的事件。
v$lock 列出系統(tǒng)中的所有的鎖。 Sid:表示持有鎖的會話信息。
Type:表示鎖的類型。值包括TM和TX等。
ID1:表示鎖的對象標(biāo)識。
lmode,request:表示會話等待的鎖模式的信
息。用數(shù)字0-6表示,和表1相對應(yīng)。
dba_locks 對v$lock的格式化視圖。 Session_id:和v$lock中的Sid對應(yīng)。
Lock_type:和v$lock中的type對應(yīng)。
Lock_ID1: 和v$lock中的ID1對應(yīng)。
Mode_held,mode_requested:和v$lock中
的lmode,request相對應(yīng)。
v$locked_object 只包含DML的鎖信息,包括回滾段和會話信息。 Xidusn,xidslot,xidsqn:表示回滾段信息。和
v$transaction相關(guān)聯(lián)。
Object_id:表示被鎖對象標(biāo)識。
Session_id:表示持有鎖的會話信息。
Locked_mode:表示會話等待的鎖模式的信
息,和v$lock中的lmode一致。
col owner for a12
col object_name for a16
select b.owner,b.object_name,l.session_id,l.locked_mode
from v$locked_object l, dba_objects b
where b.object_id=l.object_id;
select t2.username,t2.sid,t2.serial#,t2.logon_time
from v$locked_object t1,v$session t2
where t1.session_id=t2.sid order by t2.logon_time;
如果有長期出現(xiàn)的一列,可能是沒有釋放的鎖。我們可以用下面SQL語句殺掉長期沒有釋放非正常的鎖:
alter system kill session 'sid,serial# ';
如果出現(xiàn)了鎖的問題, 某個DML操作可能等待很久沒有反應(yīng)。
當(dāng)你采用的是直接連接數(shù)據(jù)庫的方式,也不要用OS系統(tǒng)命令 $kill process_num 或者 $kill -9 process_num來終止用戶連接,因?yàn)橐粋€用戶進(jìn)程可能產(chǎn)生一個以上的鎖, 殺OS進(jìn)程并不能徹底清除鎖的問題
Oracle鎖表(死鎖) 2011-05-03 17:46:41| 分類: Java技術(shù) | 標(biāo)簽: |字號大中小 訂閱 .
數(shù)據(jù)庫與操作系統(tǒng)一樣,是一個多用戶使用的共享資源。 當(dāng)多個用戶并發(fā)地存取數(shù)據(jù)時,在數(shù)據(jù)庫中就會發(fā)生多個事務(wù)同時存取同一數(shù)據(jù)地情況。 若對并發(fā)操作不加控制就可能會讀取和存儲不正確地?cái)?shù)據(jù),破壞數(shù)據(jù)庫地一致性。 加鎖時實(shí)現(xiàn)數(shù)據(jù)庫并發(fā)控制地一個非常重要地技術(shù)。 在實(shí)際應(yīng)用中經(jīng)常會遇到地與鎖相關(guān)地異常情況,當(dāng)兩個事務(wù)需要一組有沖突的鎖,而不能將事務(wù)繼續(xù)下去的話,就會出現(xiàn)死鎖,嚴(yán)重影響應(yīng)用的正常執(zhí)行。
在數(shù)據(jù)庫中有兩種基本的鎖類型:排它鎖(Exclusive Locks,即X鎖)和共享鎖(即S鎖)。當(dāng)數(shù)據(jù)對象被加上排它鎖時,其他的事務(wù)不能不能對它讀取和修改。加了共享鎖的數(shù)據(jù)對象可以被其他事務(wù)讀取,但不能修改。數(shù)據(jù)庫利用這兩種基本的鎖類型來對數(shù)據(jù)庫的事務(wù)進(jìn)行并發(fā)控制。
死鎖的第一種情況:
一個用戶A訪問表A(鎖住了表A),然后又訪問表B; 另一個用戶B訪問表B(鎖住了表B),然后企圖訪問表A;這時用戶A由于用戶B已經(jīng)鎖住表B,它必須等待用戶B釋放表B才能繼續(xù),同樣用戶B要等用戶A釋放表A才能繼續(xù),這就死鎖產(chǎn)生了。
解決方法:
這種死鎖比較常見,是由于程序的BUG產(chǎn)生的,除了調(diào)整程序的邏輯沒有其它的辦法。仔細(xì)分析程序的邏輯,對于數(shù)據(jù)庫的多表操作時,盡量按照同樣的順序進(jìn)行處理,盡量避免同時鎖定兩個資源,如操作A和B兩張表時,總是按先A后B的順序處理,必須同時鎖定兩個資源時,要保證在任何時刻都應(yīng)該按照相同的順序來鎖定資源。
死鎖的第二種情況
用戶A查詢一條記錄,然后修改該條記錄;這時用戶B修改該條記錄,這時用戶A的事務(wù)里鎖的性質(zhì)由查詢的共享鎖企圖上升到獨(dú)占鎖,而用戶B里的獨(dú)占鎖由于A有共享鎖存在必須等A釋放掉共享鎖,而A由于B的獨(dú)占鎖而無法上升到獨(dú)占鎖也就不可能釋放共享鎖,于是出現(xiàn)了死鎖。這種死鎖比較隱蔽,但在稍大點(diǎn)的項(xiàng)目種經(jīng)常發(fā)生,如在某項(xiàng)目中,頁面上的按鈕點(diǎn)擊后,沒有使按鈕立刻失效,使得用戶會多次快速點(diǎn)擊同一按鈕,這樣同一段代碼對數(shù)據(jù)庫同一條記錄進(jìn)行多次操作,很容易就出現(xiàn)這種死鎖的情況。
解決方法:
1、對于按鈕等控件,點(diǎn)擊后使其立刻失效,不讓用戶重復(fù)點(diǎn)擊,避免對同時對同一條記錄操作。
2、使用樂觀鎖進(jìn)行控制。樂觀鎖大多是基于數(shù)據(jù)版本(version)記錄機(jī)制實(shí)現(xiàn)。即為數(shù)據(jù)增加一個版本標(biāo)識,在基于數(shù)據(jù)庫表的版本解決方案中,一般是通過為數(shù)據(jù)庫增加一個“version”字段來實(shí)現(xiàn)。讀取處數(shù)據(jù)時,將此版本號一同讀出,之后更新時,對此版本號加一。此時,將提交的數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對應(yīng)記錄的當(dāng)前版本信息進(jìn)行比對,如果提交的數(shù)據(jù)版本號大于數(shù)據(jù)庫表當(dāng)前版本號,則予以更新,否則認(rèn)為是過期數(shù)據(jù)。樂觀鎖機(jī)制避免了長事務(wù)中的數(shù)據(jù)庫加鎖開銷(用戶A和用戶B操作過程中,都沒有對數(shù)據(jù)庫加鎖),大大提升了大并發(fā)量下的系統(tǒng)整體性表現(xiàn)。 Hibernate在其數(shù)據(jù)訪問引擎中內(nèi)置了樂觀鎖實(shí)現(xiàn)。需要注意的是,由于樂觀鎖機(jī)制是我們的系統(tǒng)中實(shí)現(xiàn),來自外部系統(tǒng)的用戶更新操作不受我們系統(tǒng)的控制,因此可能會造成臟數(shù)據(jù)被更新到數(shù)據(jù)庫中。
3、使用悲觀鎖進(jìn)行控制。悲觀鎖大多數(shù)情況下依靠數(shù)據(jù)庫的鎖機(jī)制實(shí)現(xiàn),如Oracle的select.......for update語句,以保證操作最大程度的獨(dú)占性。但隨之而來的就是數(shù)據(jù)庫性能的大量開銷,特別是對長事務(wù)而言,這樣的開銷往往無法承受。如一個金融系統(tǒng),當(dāng)某個操作員讀取用戶的數(shù)據(jù),并在讀出的用戶數(shù)據(jù)的基礎(chǔ)上進(jìn)行修改時(如更改用戶帳戶余額),如果采用悲觀鎖機(jī)制,也就意味整個操作過程中(從操作員讀出數(shù)據(jù)、開始修改直至提交修改結(jié)果的全過程,甚至還包括操作員中途去煮咖啡的時間),數(shù)據(jù)庫記錄始終處于加鎖狀態(tài),可以想見,如果面對成百上千個并發(fā),這樣的情況將導(dǎo)致災(zāi)難性的結(jié)果。所以,采用悲觀鎖進(jìn)行控制時一定要考慮清楚。
死鎖的第三種情況
如果在事務(wù)種執(zhí)行了一條不滿足條件的update語句,則執(zhí)行全表掃描,把行級鎖上升為表級鎖,多個這樣的事務(wù)執(zhí)行之后,就很容易發(fā)生死鎖和阻塞。類似的情況還有當(dāng)表種的數(shù)據(jù)量非常龐大而索引建的過少或不合適的時候,使得經(jīng)常發(fā)生全表掃描,最終應(yīng)用系統(tǒng)會越來越慢,最終發(fā)生阻塞或死鎖。
解決方法:
SQL語句中不要使用太復(fù)雜的關(guān)聯(lián)多表的查詢;使用“執(zhí)行計(jì)劃”對SQL語句進(jìn)行 分析,對于有全表掃描的SQL語句,建立相應(yīng)的索引進(jìn)行優(yōu)化。
***查詢死鎖表以及解鎖表***
通過select * from v$locked_object
可以獲得被鎖的對象的object_id及產(chǎn)生鎖的會話sid,通過查詢結(jié)果中的object_id,可以查詢到具體被鎖的對象。
鎖有以下幾種模式:
0:none
1:null 空
2:Row-S 行共享(RS / S鎖):共享表鎖
3:Row-X 行專用(RX / X鎖):用于行的修改
4:Share 共享鎖(S):阻止其他DML操作
5:S/Row-X 共享行專用(SRX):阻止其他事務(wù)操作
6:exclusive 專用(X):獨(dú)立訪問使用
數(shù)字越大鎖級別越高, 影響的操作越多。
一般的查詢語句如select ... from ... ;是小于2的鎖, 有時會在v$locked_object出現(xiàn)。
select ... from ... for update; 是2的鎖。
當(dāng)對話使用for update子串打開一個游標(biāo)時,
所有返回集中的數(shù)據(jù)行都將處于行級(Row-X)獨(dú)占式鎖定,
其他對象只能查詢這些數(shù)據(jù)行,不能進(jìn)行update、delete或select...for update操作。
insert / update / delete ... ; 是3的鎖。
沒有commit之前插入同樣的一條記錄會沒有反應(yīng),
因?yàn)楹笠粋€3的鎖會一直等待上一個3的鎖, 我們必須釋放掉上一個才能繼續(xù)工作。
創(chuàng)建索引的時候也會產(chǎn)生3,4級別的鎖。
locked_mode為2,3,4不影響DML(insert,delete,update,select)操作,
但DDL(alter,drop等)操作會提示ora-00054錯誤。
有主外鍵約束時 update / delete ... ; 可能會產(chǎn)生4,5的鎖。
DDL語句時是6的鎖。
以DBA角色, 查看當(dāng)前數(shù)據(jù)庫里鎖的情況可以用如下SQL語句:
select object_id,session_id,locked_mode from v$locked_object;
select t2.username,t2.sid,t2.serial#,t2.logon_time
from v$locked_object t1,v$session t2
where t1.session_id=t2.sid order by t2.logon_time;
如果有長期出現(xiàn)的一列,可能是沒有釋放的鎖。
我們可以用下面SQL語句殺掉長期沒有釋放非正常的鎖:
戶A打開應(yīng)用的界面,看到數(shù)據(jù)庫的某條記錄
b.用戶B打開應(yīng)用的界面,看到同樣一條記錄
c. 用戶A對記錄做了修改
d. 對于web應(yīng)用而言[假設(shè)沒有應(yīng)用comet類似技術(shù)],通常B不知道這個修改,這時B也對同樣這條記錄做修改,那B就有可能覆蓋A做的修改;
這個問題在數(shù)據(jù)庫中被稱為丟失更新問題
2.我自己對這個問題的理解過程是這樣的:
a. 不知道這個問題
我在做開發(fā)好長時間之后才意識到這個問題,意識到這個問題之后,我后來發(fā)現(xiàn)很長一段時間內(nèi)都沒真正搞明白為什么這是個問題-_- 而且我發(fā)現(xiàn)現(xiàn)在周圍的很多同事,尤其是新畢業(yè)的學(xué)生,其實(shí)也一直過了很長時間都沒明白這個問題,這說明吧不知道這個丟失更新問題是一個非常普遍的問題:)
b.用信號量以及操作之前再次驗(yàn)證的方法解決
最開始的時候,測試發(fā)現(xiàn)了這樣一個問題,要求解決,我把操作系統(tǒng)的教科書搬來,對照著寫了一個信號量semaphore類[那時候還是jdk 1.4.2,jdk里面沒有concurrent包],花了好長時間測試這個semaphore的實(shí)現(xiàn)是正確的[重復(fù)發(fā)明輪子的血淚史..],
然后用來控制這個操作,每次操作前獲取信號量,然后驗(yàn)證,再做真正的數(shù)據(jù)庫操作。。。相當(dāng)于在應(yīng)用層每次都只做一件事。
c. 再次理解
再后來,我看了Tom的這本9i和10g的書,書中提到前面的丟失更新過程,大概有點(diǎn)明白為什么這是個問題
8a7315603d51c12ef97a82729cdc4677.png
但是其實(shí)我有個疑問,對于數(shù)據(jù)庫中的記錄而言,A做的修改本來就有可能被B覆蓋的,為什么這會是一個丟失更新問題呢? 正好項(xiàng)目里面又出現(xiàn)了類似的情況,我仔細(xì)觀察了下,終于明白為什么這是個問題,以及為什么要使用對應(yīng)的樂觀鎖悲觀鎖方案了。下面對此做詳細(xì)說明
3. 一個比較清楚的場景
下面這個假設(shè)的實(shí)際場景可以比較清楚的幫助我們理解這個問題:
假設(shè)當(dāng)當(dāng)網(wǎng)上用戶下單買了本書,這時數(shù)據(jù)庫中有條訂單號為001的訂單,其中有個status字段是’有效’,表示該訂單是有效的;
后臺管理人員查詢到這條001的訂單,并且看到狀態(tài)是有效的
用戶發(fā)現(xiàn)下單的時候下錯了,于是撤銷訂單,假設(shè)運(yùn)行這樣一條SQL: update order_table set status = ‘取消’ where order_id = 001;
后臺管理人員由于在b這步看到狀態(tài)有效的,這時,雖然用戶在c這步已經(jīng)撤銷了訂單,可是管理人員并未刷新界面,看到的訂單狀態(tài)還是有效的,于是點(diǎn)擊”發(fā)貨”按鈕,將該訂單發(fā)到物流部門,同時運(yùn)行類似如下SQL,將訂單狀態(tài)改成已發(fā)貨:update order_table set status = ‘已發(fā)貨’ where order_id = 001
如果當(dāng)當(dāng)?shù)南到y(tǒng)這樣實(shí)現(xiàn),顯然不對了,肯定要挨罵了,明明已經(jīng)取消了訂單,為什么還會發(fā)貨呢?而且確實(shí)取消訂單的操作發(fā)生在發(fā)貨操作之前啊。 因?yàn)樵谶@樣的實(shí)現(xiàn)下,后臺管理人員無論怎么做都有可能會出錯,因?yàn)樗蜷_系統(tǒng)看到有效的訂單和他點(diǎn)發(fā)貨之間肯定有個時間差,在這個時間差的時候總是存在用戶取消訂單的可能。
4. 當(dāng)時的詳細(xì)解決方法。幾年前當(dāng)測試人員告訴我系統(tǒng)存在這個問題的時候,我的解決方法是這樣的, 首先,先把操作系統(tǒng)的教科書搬來,然后對照著了一個semaphore,然后反復(fù)測試各種情況證明寫的是正確的; 然后,
1. 獲取一個信號量,保證每次只能有一個線程進(jìn)入下面的步驟
2. 檢查數(shù)據(jù)庫,看這條訂單是否狀態(tài)是有效的
a. 如果有效則繼續(xù),進(jìn)入發(fā)貨步驟 b) 如果無效則返回,釋放信號量,告訴用戶狀態(tài)已經(jīng)發(fā)生改變
3. 發(fā)貨,釋放信號量
看到這里,也許很多人要罵我蠢了,直接把SQL語句改成下面這樣吧就可以了么? update order_table set status = ‘已發(fā)貨’ where order_id = 001 and status = ‘有效’ 是的,的確是這樣。雖然我當(dāng)時的項(xiàng)目的情況比和這個稍微復(fù)雜一點(diǎn),涉及到多張表格,不能直接這么做,但當(dāng)時的確不知道這個更新丟失問題,也沒想到合適的類似方式,于是就在應(yīng)用層做了這么一個每次實(shí)際上只能有一個用戶在做真正的更新這樣一個方式來解決,這樣做的結(jié)果是,在應(yīng)用層單獨(dú)做了類似這么一個鎖的機(jī)制。我記得當(dāng)時的項(xiàng)目畢業(yè)答辯的時候,老師問我同步的這個問題不直接用數(shù)據(jù)庫的鎖的方案來解決?我當(dāng)時胡亂回答了下,后來想起來,其實(shí)壓根沒理解老師的意思-_- 而且這樣做有一個問題,假設(shè)在特殊情況下,這條訂單被DBA直接修改了,沒有經(jīng)過應(yīng)用,那么應(yīng)用做這個操作也會是錯的,因?yàn)樵?.a到3之前的這段時間,有可能正好是DBA直接修改的時候。那么3做的操作也是不對的。 而且,現(xiàn)實(shí)情況是在后來的幾年開發(fā)過程中,我也的確在一些不同的項(xiàng)目代碼中看到,其他很多人也在使用類似的代碼解決測試人員告訴他們的這些同步問題-_-
5.正確而簡潔的解決方法
問題清楚了,也說明了我曾經(jīng)使用的解決方案也是一個簡潔直接的解決方案,純粹是把簡單問題復(fù)雜化,下面說說實(shí)際有效的解決方案; 就這個丟失更新問題,可以通過數(shù)據(jù)庫的鎖來實(shí)現(xiàn),基本兩種思路,一種是悲觀鎖,另外一種是樂觀鎖; 簡單的說就是一種假定這樣的問題是高概率的,最好一開始就鎖住,免得更新老是失敗;另外一種假定這樣的問題是小概率的,最后一步做更新的時候再鎖住,免得鎖住時間太長影響其他人做有關(guān)操作;
6. 樂觀鎖的方法
這里先說web開發(fā)中常用的樂觀鎖的方法:
1.很簡單,就是使用前面所說的這樣一條SQL,這其實(shí)是所謂使用”前鏡像”的方式來保證需要更新的數(shù)據(jù)是符合要求的,
update order_table set status = ‘已發(fā)貨’ where order_id = 001 and status = ‘有效’ Tom的書上舉的例子是對所有列做更新,所以他的SQL大致如下 Update table set col1 = newcol1value, col2 = newcol2value…. where col1 = oldcol1value and col2 = oldcol2value…. 這個我覺得需要根據(jù)應(yīng)用具體分析,如果需要判斷所有的值,那就判斷所有的值,如果只關(guān)心其中一個或部分值,那只需要取相關(guān)的值就好了,就比如這里的訂單的狀態(tài)
2.使用版本列[比如時間戳
這個方法比較簡單,也最常用,就是在數(shù)據(jù)庫表格中加一列l(wèi)ast_modified_date,就是最后更新的時間,每次更新的時候都將這列設(shè)成systimestamp,當(dāng)前系統(tǒng)時間;
然后每次更新的時候,就改成這樣 Update table set col = newvalue where id = ** and last_modified_date = old last_modified_date 這樣,就可以檢驗(yàn)出數(shù)據(jù)庫的值是否在上次查看和這次更新的時候發(fā)生了變化,如果發(fā)生了變化,那么last_modified_date就變化了,以后的更新就會返回更新了0行,系統(tǒng)就可以通知用戶數(shù)據(jù)發(fā)生了變化,然后選擇刷新數(shù)據(jù)或者其他流程。
至于這個last_modified_date的維護(hù),可以選擇讓應(yīng)用每次都維護(hù)這個值,或者是使用存儲過程來包裝更新的操作,或者是使用觸發(fā)器來更新相關(guān)的值。幾種方法各有利弊,比如應(yīng)用維護(hù)需要保證每段相關(guān)代碼都正確的維護(hù)了這個值;存儲過程有一定的開銷,通常很多開發(fā)對寫存儲過程可能也不熟練;觸發(fā)器是簡單的實(shí)現(xiàn),但是也是有開銷的。具體使用哪種方法需要根據(jù)實(shí)際情況具體取舍。
3.使用校驗(yàn)或Hash值
這種方法和前面的方法類似,無非是根據(jù)其他有實(shí)際意義的列來計(jì)算出一個虛擬的列,我個人覺得TOM在介紹這個純粹是介紹了一種”奇技淫巧”,反正我是在實(shí)際過程中不知道哪里會需要這樣的解決方案,或許也是因?yàn)槲抑赖奶倭税桑?
4.使用Oracle 10g的ORA_ROWSCN
這個就是利用10g的一個ora_rowscn特性,可以對每行做精確追蹤,不過這個要求在create table的時候就指定相關(guān)參數(shù),表格如果創(chuàng)建了以后就不能用alter table來修改了,因?yàn)檫@依賴于物理的實(shí)際存儲。 同樣,我覺得這也可以歸為”奇技淫巧”一類; 具體如果有興趣了解詳情的話,可以參考Tom的書
我們一直都在努力堅(jiān)持原創(chuàng).......請不要一聲不吭,就悄悄拿走。
我原創(chuàng),你原創(chuàng),我們的內(nèi)容世界才會更加精彩!
【所有原創(chuàng)內(nèi)容版權(quán)均屬TechTarget,歡迎大家轉(zhuǎn)發(fā)分享。但未經(jīng)授權(quán),嚴(yán)禁任何媒體(平面媒體、網(wǎng)絡(luò)媒體、自媒體等)以及微信公眾號復(fù)制、轉(zhuǎn)載、摘編或以其他方式進(jìn)行使用?!?/p>
微信公眾號
TechTarget
官方微博
TechTarget中國
相關(guān)資源:oracle樂觀鎖和悲觀鎖詳細(xì)教程_oracle的樂觀鎖-Oracle文檔類資源...
點(diǎn)擊閱讀全文
打開CSDN,閱讀體驗(yàn)更佳
Oracle數(shù)據(jù)庫悲觀鎖與樂觀鎖_diweikang的博客
注:對于悲觀鎖是針對并發(fā)的可能性比較大,而一般在我們的應(yīng)用中用樂觀鎖足以。 Oracle的悲觀鎖需要利用一條現(xiàn)有的連接,分成兩種方式,從SQL語句的區(qū)別來看,就是一種是for update,一種是for update nowait的形式。 1. 執(zhí)行select xxx ...
ORACLE悲觀鎖和樂觀鎖_hongwei3344661的博客
1、無論是選擇悲觀鎖策略,還是樂觀鎖策略。如果一個對象被上了鎖,那么該對象都會受這個鎖的控制和影響。 2、選擇悲觀鎖策略,還是樂觀鎖策略,這主要是由應(yīng)用和業(yè)務(wù)需求來確定的。如果你的應(yīng)用和業(yè)務(wù)經(jīng)常會出現(xiàn)從我看到要修改的記錄的...
oracle 樂觀鎖和悲觀鎖詳細(xì)教程
詳細(xì)介紹了Oracle中樂觀鎖、悲觀鎖的原理及應(yīng)用,并有實(shí)例
基于ORACLE的樂觀鎖實(shí)現(xiàn)原理
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn) ...
繼續(xù)訪問
Oracle之悲觀鎖和樂觀鎖_hys21的博客
根據(jù)保護(hù)的對象不同,Oracle數(shù)據(jù)庫鎖可以分為以下幾大類:DML鎖(data locks,數(shù)據(jù)鎖),用于實(shí)現(xiàn)并發(fā)存取并保護(hù)數(shù)據(jù)的完整性;DDL鎖(dictionary locks,字典鎖),用于保護(hù)數(shù)據(jù)庫對象的結(jié)構(gòu),如表、索引等的結(jié)構(gòu)定義;內(nèi)部鎖和閂(internal locks ...
oracle樂觀鎖和悲觀鎖詳細(xì)教程_oracle的樂觀鎖-Oracle文檔類資源...
內(nèi)部包含oracle百度網(wǎng)盤下載鏈接以及密碼。 oci.dll 12版本全部 資源是從Oracle官方網(wǎng)站下載,已測試可用 【白雪紅葉】JAVA學(xué)習(xí)技術(shù)棧梳理思維導(dǎo)圖.xmind 樂觀鎖行級鎖 分布式鎖 分區(qū)排隊(duì) 一致性 一致性算法 paxos zab nwr raft gossip ...
Oracle創(chuàng)建悲觀鎖和樂觀鎖
為了得到最大的性能,一般數(shù)據(jù)庫都有并發(fā)機(jī)制,不過帶來的問題就是數(shù)據(jù)訪問的沖突。為了解決這個問題,大多數(shù)數(shù)據(jù)庫用的方法就是數(shù)據(jù)的鎖定。 考慮下面的情況。如果我們先查詢到數(shù)據(jù),然后更新數(shù)據(jù)。這樣會出現(xiàn)這樣的情況。A線程查詢的時候,B線程也在查詢,當(dāng)A線程準(zhǔn)備更新的時候,B線程先獲得 了更新鎖,將這些行鎖定了。A只能等待B更新完。當(dāng)B線程更新完釋放鎖的時候,A獲得鎖,這時A會識別出字段已經(jīng)
繼續(xù)訪問
Oracle并發(fā)控制中的樂觀鎖
數(shù)據(jù)庫的管理員要分散他們的數(shù)據(jù)庫,以便處理基于Web,B2B,電子商務(wù)的訪問,快速的硬盤讀寫以及更多的資源或許只能解決一部分問題。疲乏的鎖機(jī)制甚至?xí)魅鯎碛泻芎觅Y源的應(yīng)用性能。樂觀鎖可以大大改善具有較多事務(wù)處理的數(shù)據(jù)庫載入性能,比如基于web的客戶端訪問。 悲觀鎖引發(fā)的問題: 大多數(shù)Oracle開發(fā)者已經(jīng)非常熟悉悲觀鎖,即在對數(shù)據(jù)進(jìn)行更新之前給數(shù)據(jù)加鎖。使用熟悉的SELECT...FOR UP
繼續(xù)訪問
oracle樂觀鎖悲觀鎖學(xué)習(xí)筆記(更新中)_Evaron.Z的博客
首先解釋下樂觀鎖和悲觀鎖的含義 樂觀鎖:樂觀鎖就是認(rèn)為數(shù)據(jù)一般情況下不會造成沖突,所以在數(shù)據(jù)進(jìn)行提交更新的時候,才會正式對數(shù)據(jù)的沖突與否進(jìn)行檢測,如果發(fā)現(xiàn)沖突了,則返回錯誤的信息。 悲觀鎖:悲觀鎖就是對數(shù)據(jù)的沖突采取一種悲觀的...
【Oracle】樂觀鎖和悲觀鎖_◣NSD◥的博客_oracle悲觀鎖...
樂觀鎖對應(yīng)于生活中樂觀的人總是想著事情往好的方向發(fā)展,悲觀鎖對應(yīng)于生活中悲觀的人總是想著事情往壞的方向發(fā)展。這兩種人各有優(yōu)缺點(diǎn),不能不以場景而定說一種人好于另外一種人。 悲觀鎖 ...
Oracle樂觀鎖悲觀鎖
1.樂觀鎖 當(dāng)處理對象狀態(tài)時為了防止沖突 例:一個下訂單的狀態(tài)status a.更新status為1購買,b取得status為1,這時a要退貨把status改為2. 這時如果b還按1的狀態(tài)去處理,發(fā)貨了。就出錯了。 正確的做法為: 當(dāng)b發(fā)貨時,為了處理并發(fā)臟讀,需要先根據(jù)原status狀態(tài)去更新status為3訂單處理中 int res = update...
繼續(xù)訪問
【轉(zhuǎn)】 Oracle中樂觀鎖定的四種實(shí)現(xiàn)方式
br /Oracle中樂觀鎖定的四種實(shí)現(xiàn)方式br / br /轉(zhuǎn)自 ;br / 更新前在應(yīng)用中存儲所要操作行的“前映像”,更新時使用存儲的舊記錄來判斷當(dāng)前值是否已經(jīng)改變; 使用一個特殊的列,這個列由一個數(shù)據(jù)庫觸發(fā)器或應(yīng)用程序代碼維護(hù),可以告訴我們記錄的 “版本”; 使用一個校驗(yàn)和或散列值,這是使用原來的數(shù)據(jù)計(jì)算得出的; 使用新增的 Oracle 10g 特性 ORA_R
繼續(xù)訪問
oracle的悲觀鎖和樂觀鎖
目錄 1 悲觀鎖 1.1 單表 for update 1.2 關(guān)聯(lián)表for update 1.3 解除for update 鎖的占用 1.4 悲觀鎖缺點(diǎn) 2 樂觀鎖 2.1 比對法 2.2 版本戳 2.3 timestamp型 2.4 例子Demo 問select *from person for update或update perso...
繼續(xù)訪問
Oracle的悲觀鎖和樂觀鎖
為了得到最大的性能,一般數(shù)據(jù)庫都有并發(fā)機(jī)制,不過帶來的問題就是數(shù)據(jù)訪問的沖突。為了解決這個問題,大多數(shù)數(shù)據(jù)庫用的方法就是數(shù)據(jù)的鎖定。 數(shù)據(jù)的鎖定分為兩種方法,第一種叫做悲觀鎖,第二種叫做樂觀鎖。什么叫悲觀鎖呢,悲觀鎖顧名思義,...
繼續(xù)訪問
oracle鎖機(jī)制之悲觀鎖與樂觀鎖以及for update用法
目錄 1 悲觀鎖 1.1 單表 for update 1.2關(guān)聯(lián)表for update 1.3 悲觀鎖缺點(diǎn) 2樂觀鎖 2.1 比對法 2.2版本戳 2.3timestamp型 2.4 例子Demo 1 悲觀鎖 所謂的悲觀鎖:顧名思義,就是很悲觀,每次去拿數(shù)據(jù)的時候都認(rèn)為別人會修改,所以每次拿數(shù)據(jù)的時候都會上鎖。這樣別人拿數(shù)據(jù)的時候就要等待直到鎖的釋放。 數(shù)據(jù)庫行級...
繼續(xù)訪問
oracle的樂觀鎖和悲觀鎖
一、問題引出 ① 假設(shè)當(dāng)當(dāng)網(wǎng)上用戶下單買了本書,這時數(shù)據(jù)庫中有條訂單號為001的訂單,其中有個status字段是’有效’,表示該訂單是有效的; ② 后臺管理人員查詢到這條001的訂單,并且看到狀態(tài)是有效的; ③ 用戶發(fā)現(xiàn)下單的時候下錯了,于是撤銷訂單,假設(shè)運(yùn)行這樣一條SQL: update order_table set status = ‘取消’ whe
繼續(xù)訪問
Oracle鎖定:悲觀與樂觀鎖詳解
Oracle數(shù)據(jù)庫悲觀鎖與樂觀鎖是本文我們主要要介紹的內(nèi)容。有時候?yàn)榱说玫阶畲蟮男阅?,一般?shù)據(jù)庫都有并發(fā)機(jī)制,不過帶來的問題就是數(shù)據(jù)訪問的沖突。為了解決這個問題,大多數(shù)數(shù)據(jù)庫用的方法就是數(shù)據(jù)的鎖定…… 以下是代碼片段: select*fromtestwhereid=10也就是沒有for update這種鎖定數(shù)據(jù)的語句的話,就不會造成阻塞了。另外一種情況,就是當(dāng)數(shù)據(jù)庫數(shù)據(jù)被鎖定的時候,也
繼續(xù)訪問
樂觀鎖與悲觀鎖——解決并發(fā)問題
引言 為什么需要鎖(并發(fā)控制)? 在多用戶環(huán)境中,在同一時間可能會有多個用戶更新相同的記錄,這會產(chǎn)生沖突。這就是著名的并發(fā)性問題。 典型的沖突有: 丟失更新:一個事務(wù)的更新覆蓋了其它事務(wù)的更新結(jié)果,就是所謂的更新丟失。例如:用戶A把值從6改為2,用戶B把值從2改為6,則用戶A丟失了他的更新。 臟讀:當(dāng)一個事務(wù)讀取其它完成一半事務(wù)的記錄時,就會發(fā)生臟讀取。例如:用戶A,B看到的...
繼續(xù)訪問
樂觀鎖和悲觀鎖策略的區(qū)別與實(shí)現(xiàn)
樂觀鎖和悲觀鎖策略的區(qū)別與實(shí)現(xiàn) 1、無論是選擇悲觀鎖策略,還是樂觀鎖策略。如果一個對象被上了鎖,那么該對象都會受這個鎖的控制和影響。如果這個鎖是個排它鎖,那么其它會話都不...
繼續(xù)訪問
oracle的共享鎖不起作用,ORACLE中的樂觀鎖、悲觀鎖、共享鎖、排他鎖
一、引入在數(shù)據(jù)庫操作中,如果不同的用戶或者事務(wù)并發(fā)地訪問同一數(shù)據(jù),可能就會破壞數(shù)據(jù)到完整性,這時候我們就可以用鎖來保證數(shù)據(jù)的一致性。二、概念1. 悲觀鎖就是很悲觀地任認(rèn)為我每次要修改數(shù)據(jù)時,其他的操作總會來改變我要修改的數(shù)據(jù),于是就將其加鎖。這樣一來,其他人只能等待我先放開鎖后才能操作數(shù)據(jù)。請看以下的示例。造數(shù):CREATE TABLE test_yyw(id NUMBER(4),name VAR...
繼續(xù)訪問
oracle 鎖定 問題
鎖(lock)機(jī)制用于管理對共享資源的并發(fā)訪問。 數(shù)據(jù)庫中使用鎖是為了支持對共享資源進(jìn)行并發(fā)訪問,與此同時還能提供數(shù)據(jù)完整性和一致性。 在Oracle中,你會了解到: ? 事務(wù)是每個數(shù)據(jù)庫的核心,它們是“好東西”。 ? 應(yīng)該延遲到適當(dāng)?shù)臅r刻才提交。不要太快提交,以避免對系統(tǒng)帶來壓力。這是因?yàn)?,如果事?wù)很長或很大,一般不會對系統(tǒng)有壓力。相應(yīng)的原則是:在必要時才提交,但是此前不要提
繼續(xù)訪問
最新發(fā)布 oracle數(shù)據(jù)庫加悲觀鎖,Oracle 悲觀鎖跟樂觀鎖
EMPNO ENAME SAL7782 CLARK 2450.007839 KING 5000.007934 MILLER 1300.00在SQLplus中模擬應(yīng)用可能執(zhí)行的綁定調(diào)用,可以利用下面命名:SQL variable empno numberSQL variable ename varchar2(20)SQL var...
繼續(xù)訪問
Oracle 樂觀鎖、悲觀鎖
oracle有悲觀鎖也有樂觀鎖。 悲觀鎖比較安全一些,可以防止丟失更新,但是就是互相等待,影響效率。 一般會用樂觀鎖,即開始操作時,樂觀的認(rèn)為數(shù)據(jù)不會被其他人更改,直到提交時才加鎖檢查。比如在操作的表上加一列,保存?zhèn)€時間戳,提交時檢查是不是最新的。不過樂觀鎖失敗的可能性比較大。 樂觀鎖,大多是基于數(shù)據(jù)版本( Version )記錄機(jī)制實(shí)現(xiàn)。
繼續(xù)訪問
oracle樂觀鎖實(shí)例
oracle 悲觀鎖和樂觀鎖
寫評論
評論
收藏
點(diǎn)贊
踩
分享
前往CSDN APP閱讀全文
閱讀體驗(yàn)更佳
CSDN
成就一億技術(shù)人
前往
為了得到最大的性能,一般數(shù)據(jù)庫都有并發(fā)機(jī)制,不過帶來的問題就是數(shù)據(jù)訪問的沖突。為了解決這個問題,大多數(shù)數(shù)據(jù)庫用的方法就是數(shù)據(jù)的鎖定。
數(shù)據(jù)的鎖定分為兩種方法,第一種叫做悲觀鎖,第二種叫做樂觀鎖。什么叫悲觀鎖呢,悲觀鎖顧名思義,就是對數(shù)據(jù)的沖突采取一種悲觀的態(tài)度,也就是說假設(shè)數(shù)據(jù)肯定會沖突,所以在數(shù)據(jù)開始讀取的時候就把數(shù)據(jù)鎖定住。而樂觀鎖就是認(rèn)為數(shù)據(jù)一般情況下不會造成沖突,所以在數(shù)據(jù)進(jìn)行提交更新的時候,才會正式對數(shù)據(jù)的沖突與否進(jìn)行檢測,如果發(fā)現(xiàn)沖突了,則讓用戶返回錯誤的信息,讓用戶決定如何去做。
先從悲觀鎖開始說。在SqlServer等其余很多數(shù)據(jù)庫中,數(shù)據(jù)的鎖定通常采用頁級鎖的方式,也就是說對一張表內(nèi)的數(shù)據(jù)是一種串行化的更新插入機(jī)制,在任何時間同一張表只會插1條數(shù)據(jù),別的想插入的數(shù)據(jù)要等到這一條數(shù)據(jù)插完以后才能依次插入。帶來的后果就是性能的降低,在多用戶并發(fā)訪問的時候,當(dāng)對一張表進(jìn)行頻繁操作時,會發(fā)現(xiàn)響應(yīng)效率很低,數(shù)據(jù)庫經(jīng)常處于一種假死狀態(tài)。而Oracle用的是行級鎖,只是對想鎖定的數(shù)據(jù)才進(jìn)行鎖定,其余的數(shù)據(jù)不相干,所以在對Oracle表中并發(fā)插數(shù)據(jù)的時候,基本上不會有任何影響。
注:對于悲觀鎖是針對并發(fā)的可能性比較大,而一般在我們的應(yīng)用中用樂觀鎖足以。
Oracle的悲觀鎖需要利用一條現(xiàn)有的連接,分成兩種方式,從SQL語句的區(qū)別來看,就是一種是for update,一種是for update nowait的形式。比如我們看一個例子。首先建立測試用的數(shù)據(jù)庫表。
CREATE TABLE TEST(ID,NAME,LOCATION,VALUE,CONSTRAINT test_pk PRIMARY KEY(ID))AS SELECT deptno, dname, loc, 1 FROM scott.dept
這里我們利用了Oracle的Sample的scott用戶的表,把數(shù)據(jù)copy到我們的test表中。首先我們看一下for update鎖定方式。首先我們執(zhí)行如下的select for update語句。
select * from test where id = 10 for update
通過這條檢索語句鎖定以后,再開另外一個sql*plus窗口進(jìn)行操作,再把上面這條sql語句執(zhí)行一便,你會發(fā)現(xiàn)sqlplus好像死在那里了,好像檢索不到數(shù)據(jù)的樣子,但是也不返回任何結(jié)果,就屬于卡在那里的感覺。這個時候是什么原因呢,就是一開始的第一個Session中的select for update語句把數(shù)據(jù)鎖定住了。由于這里鎖定的機(jī)制是wait的狀態(tài)(只要不表示nowait那就是wait),所以第二個Session(也就是卡住的那個sql*plus)中當(dāng)前這個檢索就處于等待狀態(tài)。當(dāng)?shù)谝粋€session最后commit或者rollback之后,第二個session中的檢索結(jié)果就是自動跳出來,并且也把數(shù)據(jù)鎖定住。不過如果你第二個session中你的檢索語句如下所示。
select * from test where id = 10
也就是沒有for update這種鎖定數(shù)據(jù)的語句的話,就不會造成阻塞了。另外一種情況,就是當(dāng)數(shù)據(jù)庫數(shù)據(jù)被鎖定的時候,也就是執(zhí)行剛才for update那條sql以后,我們在另外一個session中執(zhí)行for update nowait后又是什么樣呢。比如如下的sql語句。 由于這條語句中是制定采用nowait方式來進(jìn)行檢索,所以當(dāng)發(fā)現(xiàn)數(shù)據(jù)被別的session鎖定中的時候,就會迅速返回ORA-00054錯誤,內(nèi)容是資源正忙, 但指定以 NOWAIT 方式獲取資源。所以在程序中我們可以采用nowait方式迅速判斷當(dāng)前數(shù)據(jù)是否被鎖定中,如果鎖定中的話,就要采取相應(yīng)的業(yè)務(wù)措施進(jìn)行處理。
select * from test where id = 10 for update nowait
那這里另外一個問題,就是當(dāng)我們鎖定住數(shù)據(jù)的時候,我們對數(shù)據(jù)進(jìn)行更新和刪除的話會是什么樣呢。比如同樣,我們讓第一個Session鎖定住id=10的那條數(shù)據(jù),我們在第二個session中執(zhí)行如下語句。
update test set value=2 where id = 10
這個時候我們發(fā)現(xiàn)update語句就好像select for update語句一樣也停住卡在這里,當(dāng)你第一個session放開鎖定以后update才能正常運(yùn)行。當(dāng)你update運(yùn)行后,數(shù)據(jù)又被你update語句鎖定住了,這個時候只要你update后還沒有commit,別的session照樣不能對數(shù)據(jù)進(jìn)行鎖定更新等等。
總之,Oracle中的悲觀鎖就是利用Oracle的Connection對數(shù)據(jù)進(jìn)行鎖定。在Oracle中,用這種行級鎖帶來的性能損失是很小的,只是要注意程序邏輯,不要給你一不小心搞成死鎖了就好。而且由于數(shù)據(jù)的及時鎖定,在數(shù)據(jù)提交時候就不呼出現(xiàn)沖突,可以省去很多惱人的數(shù)據(jù)沖突處理。缺點(diǎn)就是你必須要始終有一條數(shù)據(jù)庫連接,就是說在整個鎖定到最后放開鎖的過程中,你的數(shù)據(jù)庫聯(lián)接要始終保持住。與悲觀鎖相對的,我們有了樂觀鎖。樂觀鎖一開始也說了,就是一開始假設(shè)不會造成數(shù)據(jù)沖突,在最后提交的時候再進(jìn)行數(shù)據(jù)沖突檢測。在樂觀鎖中,我們有3種
常用的做法來實(shí)現(xiàn)。
[1]第一種就是在數(shù)據(jù)取得的時候把整個數(shù)據(jù)都copy到應(yīng)用中,在進(jìn)行提交的時候比對當(dāng)前數(shù)據(jù)庫中的數(shù)據(jù)和開始的時候更新前取得的數(shù)據(jù)。當(dāng)發(fā)現(xiàn)兩個數(shù)據(jù)一模一樣以后,就表示沒有沖突可以提交,否則則是并發(fā)沖突,需要去用業(yè)務(wù)邏輯進(jìn)行解決。
[2]第二種樂觀鎖的做法就是采用版本戳,這個在Hibernate中得到了使用。采用版本戳的話,首先需要在你有樂觀鎖的數(shù)據(jù)庫table上建立一個新的column,比如為number型,當(dāng)你數(shù)據(jù)每更新一次的時候,版本數(shù)就會往上增加1。比如同樣有2個session同樣對某條數(shù)據(jù)進(jìn)行操作。兩者都取到當(dāng)前的數(shù)據(jù)的版本號為1,當(dāng)?shù)谝粋€session進(jìn)行數(shù)據(jù)更新后,在提交的時候查看到當(dāng)前數(shù)據(jù)的版本還為1,和自己一開始取到的版本相同。就正式提交,然后把版本號增加1,這個時候當(dāng)前數(shù)據(jù)的版本為2。當(dāng)?shù)诙€session也更新了數(shù)據(jù)提交的時候,發(fā)現(xiàn)數(shù)據(jù)庫中版本為2,和一開始這個session取到的版本號不一致,就知道別人更新過此條數(shù)據(jù),這個
時候再進(jìn)行業(yè)務(wù)處理,比如整個Transaction都Rollback等等操作。在用版本戳的時候,可以在應(yīng)用程序側(cè)使用版本戳的驗(yàn)證,也可以在數(shù)據(jù)庫側(cè)采用Trigger(觸發(fā)器)來進(jìn)行驗(yàn)證。不過數(shù)據(jù)庫的Trigger的性能開銷還是比較的大,所以能在應(yīng)用側(cè)進(jìn)行驗(yàn)證的話還是推薦不用Trigger。
[3]第三種做法和第二種做法有點(diǎn)類似,就是也新增一個Table的Column,不過這次這個column是采用timestamp型,存儲數(shù)據(jù)最后更新的時間。在Oracle9i以后可以采用新的數(shù)據(jù)類型,也就是timestamp with time zone類型來做時間戳。這種Timestamp的數(shù)據(jù)精度在Oracle的時間類型中是最高的,精確到微秒(還沒與到納秒的級別),一般來說,加上數(shù)據(jù)庫處理時間和人的思考動作時間,微秒級別是非常非常夠了,其實(shí)只要精確到毫秒甚至秒都應(yīng)該沒有什么問題。和剛才的版本戳類似,也是在更新提交的時候檢查當(dāng)前數(shù)據(jù)庫中數(shù)據(jù)的時間戳和自己更新前取到的時間戳進(jìn)行對比,如果一致則OK,否則就是版本沖突。如果不想把代碼寫在程序中或者由于別的原因無法把代碼寫在現(xiàn)有的程序中,也可以把這個時間戳樂觀鎖邏輯寫在Trigger或者存儲過程中。
不知道這個是不是你需要的...
數(shù)據(jù)庫事務(wù)及隔離級別
隔離級別:臟讀、幻讀、一致讀、不可重復(fù)讀、更新丟失
1.臟讀(Dirty Reads):一個事務(wù)開始讀取了某行數(shù)據(jù)但是另外一個事務(wù)已經(jīng)更新了此數(shù)據(jù)但沒有能夠及時提交。這是相當(dāng)危險很可能所有操作都被回滾
2.幻讀(Phantom Reads):也稱為幻像(幻影)。事務(wù)在操作過程中進(jìn)行兩次查詢,第二次查詢結(jié)果包含了第一次查詢中未出現(xiàn)的數(shù)據(jù)(這里并不要求兩次查詢SQL語句相同)這是因?yàn)樵趦纱尾樵冞^程中有另外一個事務(wù)插入數(shù)據(jù)造成的
3.不可重復(fù)讀(Non-repeatable Reads):一個事務(wù)對同一行數(shù)據(jù)重復(fù)讀取兩次但是卻得到了不同結(jié)果。例如在兩次讀取中途有另外一個事務(wù)對該行數(shù)據(jù)進(jìn)行了修改并提交
4.兩次更新問題(Second lost updates problem):無法重復(fù)讀取特例,有兩個并發(fā)事務(wù)同時讀取同一行數(shù)據(jù)然后其中一個對它進(jìn)行修改提交而另一個也進(jìn)行了修改提交這就會造成第一次寫操作失效
5.更新丟失(Lost update):兩個事務(wù)都同時更新一行數(shù)據(jù)但是第二個事務(wù)卻中途失敗退出導(dǎo)致對數(shù)據(jù)兩個修改都失效了這是系統(tǒng)沒有執(zhí)行任何鎖操作因此并發(fā)事務(wù)并沒有被隔離開
20、鎖是什么?
鎖:在所有的DBMS(數(shù)據(jù)庫管理系統(tǒng))中,鎖是實(shí)現(xiàn)事務(wù)的關(guān)鍵,鎖可以保證事務(wù)的完整性和并發(fā)性。與現(xiàn)實(shí)生活中鎖一樣,它可以使某些數(shù)據(jù)的擁有者,在某段時間內(nèi)不能使用某些數(shù)據(jù)或數(shù)據(jù)結(jié)構(gòu)。當(dāng)然鎖還分級別的。
鎖分為行級鎖和表鎖。
行級鎖:主要是在執(zhí)行操作過程中,鎖定指定的行。
主要的鎖行語句有:insert ,update,delete ,及select ....for update。
表鎖:指在運(yùn)行操作指令過程中,由用戶指定鎖定某張表。lock table XXX in mode share;
共享鎖,排他鎖,共享排它,行共享,行排他。
鎖模式包括?
共享鎖:(讀?。┎僮鲃?chuàng)建的鎖。其他用戶可以并發(fā)讀取數(shù)據(jù),但任何事物都不能獲取數(shù)據(jù)上的排它鎖,直到已釋放所有共享鎖。
排他鎖(X鎖):對數(shù)據(jù)A加上排他鎖后,則其他事務(wù)不能再對A加任任何類型的封鎖。獲準(zhǔn)排他鎖的事務(wù)既能讀數(shù)據(jù),又能修改數(shù)據(jù)。
更新鎖:更新 (U) 鎖可以防止通常形式的死鎖。如果兩個事務(wù)獲得了資源上的共享模式鎖,然后試圖同時更新數(shù)據(jù),則兩個事務(wù)需都要轉(zhuǎn)換共享鎖為排它 (X) 鎖,并且每個事務(wù)都等待另一個事務(wù)釋放共享模式鎖,因此發(fā)生死鎖。
若要避免這種潛 在的死鎖問題,請使用更新 (U) 鎖。一次只有一個事務(wù)可以獲得資源的更新 (U) 鎖。如果事務(wù)修改資源,則更新 (U) 鎖轉(zhuǎn)換為排它 (X) 鎖。否則,鎖轉(zhuǎn)換為共享鎖。
鎖的粒度主要有以下幾種類型:
行鎖: 粒度最小,并發(fā)性最高
頁鎖:一次鎖定一頁。25個行鎖可升級為一個頁鎖。
表鎖:粒度大,并發(fā)性低
數(shù)據(jù)庫鎖:控制整個數(shù)據(jù)庫操作
樂觀鎖:樂觀鎖假設(shè)認(rèn)為數(shù)據(jù)一般情況下不會造成沖突,所以在數(shù)據(jù)進(jìn)行提交更新的時候,才會正式對數(shù)據(jù)的沖突與否進(jìn)行檢測,如果發(fā)現(xiàn)沖突了,則讓返回用戶錯誤的信息,讓用戶決定如何去做。一般的實(shí)現(xiàn)樂觀鎖的方式就是記錄數(shù)據(jù)版本。
悲觀鎖:每次去拿數(shù)據(jù)的時候都認(rèn)為別人會修改,所以每次在拿數(shù)據(jù)的時候都會上鎖,這樣別人想拿這個數(shù)據(jù)就會block直到它拿到鎖。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫里邊就用到了很多這種鎖機(jī)制,比如行鎖,表鎖,讀鎖,寫鎖等,都是在做操作之前先上鎖。
20、數(shù)據(jù)庫的樂觀鎖和悲觀鎖是什么? oracle 是行級鎖
數(shù)據(jù)庫管理系統(tǒng)(DBMS)中,并發(fā)控制的任務(wù)是:確保在多個事務(wù)同時存取同一數(shù)據(jù)時,不破壞事務(wù)的隔離性和統(tǒng)一性以及數(shù)據(jù)庫的統(tǒng)一性。
悲觀鎖:假定會發(fā)生并發(fā)沖突,屏蔽一切可能違反數(shù)據(jù)完整性的操作
樂觀鎖:假設(shè)不會發(fā)生并發(fā)沖突,只在提交操作時檢查是否違反數(shù)據(jù)完整性。
21、悲觀鎖和樂觀鎖的區(qū)別,怎么實(shí)現(xiàn)
悲觀鎖:一段執(zhí)行邏輯加上悲觀鎖,不同線程同時執(zhí)行時,只能有一個線程執(zhí)行,其他的線程在入口處等待,直到鎖被釋放。
樂觀鎖:一段執(zhí)行邏輯加上樂觀鎖,不同線程同時執(zhí)行時,可以同時進(jìn)入執(zhí)行,在最后更新數(shù)據(jù)的時候要檢查這些數(shù)據(jù)是否被其他線程修改了(版本和執(zhí)行初是否相同),沒有修改則進(jìn)行更新,否則放棄本次操作。