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