為了得到最大的性能,一般數(shù)據(jù)庫都有并發(fā)機制,不過帶來的問題就是數(shù)據(jù)訪問的沖突。為了解決這個問題,大多數(shù)數(shù)據(jù)庫用的方法就是數(shù)據(jù)的鎖定。
創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站制作、做網(wǎng)站、河曲網(wǎng)絡(luò)推廣、小程序開發(fā)、河曲網(wǎng)絡(luò)營銷、河曲企業(yè)策劃、河曲品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎;創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供河曲建站搭建服務(wù),24小時服務(wù)熱線:18980820575,官方網(wǎng)址:vcdvsql.cn
數(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ù)是一種串行化的更新插入機制,在任何時間同一張表只會插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ù)鎖定住了。由于這里鎖定的機制是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才能正常運行。當(dāng)你update運行后,數(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ù)沖突處理。缺點就是你必須要始終有一條數(shù)據(jù)庫連接,就是說在整個鎖定到最后放開鎖的過程中,你的數(shù)據(jù)庫聯(lián)接要始終保持住。與悲觀鎖相對的,我們有了樂觀鎖。樂觀鎖一開始也說了,就是一開始假設(shè)不會造成數(shù)據(jù)沖突,在最后提交的時候再進(jìn)行數(shù)據(jù)沖突檢測。在樂觀鎖中,我們有3種
常用的做法來實現(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è)使用版本戳的驗證,也可以在數(shù)據(jù)庫側(cè)采用Trigger(觸發(fā)器)來進(jìn)行驗證。不過數(shù)據(jù)庫的Trigger的性能開銷還是比較的大,所以能在應(yīng)用側(cè)進(jìn)行驗證的話還是推薦不用Trigger。
[3]第三種做法和第二種做法有點類似,就是也新增一個Table的Column,不過這次這個column是采用timestamp型,存儲數(shù)據(jù)最后更新的時間。在Oracle9i以后可以采用新的數(shù)據(jù)類型,也就是timestamp with time zone類型來做時間戳。這種Timestamp的數(shù)據(jù)精度在Oracle的時間類型中是最高的,精確到微秒(還沒與到納秒的級別),一般來說,加上數(shù)據(jù)庫處理時間和人的思考動作時間,微秒級別是非常非常夠了,其實只要精確到毫秒甚至秒都應(yīng)該沒有什么問題。和剛才的版本戳類似,也是在更新提交的時候檢查當(dāng)前數(shù)據(jù)庫中數(shù)據(jù)的時間戳和自己更新前取到的時間戳進(jìn)行對比,如果一致則OK,否則就是版本沖突。如果不想把代碼寫在程序中或者由于別的原因無法把代碼寫在現(xiàn)有的程序中,也可以把這個時間戳樂觀鎖邏輯寫在Trigger或者存儲過程中。
不知道這個是不是你需要的...
Oracle數(shù)據(jù)庫的鎖類型
根據(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ù)據(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)象都會對實際應(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ù)或強行中斷事務(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來終止用戶連接,因為一個用戶進(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ā)操作不加控制就可能會讀取和存儲不正確地數(shù)據(jù),破壞數(shù)據(jù)庫地一致性。 加鎖時實現(xiàn)數(shù)據(jù)庫并發(fā)控制地一個非常重要地技術(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ì)由查詢的共享鎖企圖上升到獨占鎖,而用戶B里的獨占鎖由于A有共享鎖存在必須等A釋放掉共享鎖,而A由于B的獨占鎖而無法上升到獨占鎖也就不可能釋放共享鎖,于是出現(xiàn)了死鎖。這種死鎖比較隱蔽,但在稍大點的項目種經(jīng)常發(fā)生,如在某項目中,頁面上的按鈕點擊后,沒有使按鈕立刻失效,使得用戶會多次快速點擊同一按鈕,這樣同一段代碼對數(shù)據(jù)庫同一條記錄進(jìn)行多次操作,很容易就出現(xiàn)這種死鎖的情況。
解決方法:
1、對于按鈕等控件,點擊后使其立刻失效,不讓用戶重復(fù)點擊,避免對同時對同一條記錄操作。
2、使用樂觀鎖進(jìn)行控制。樂觀鎖大多是基于數(shù)據(jù)版本(version)記錄機制實現(xiàn)。即為數(shù)據(jù)增加一個版本標(biāo)識,在基于數(shù)據(jù)庫表的版本解決方案中,一般是通過為數(shù)據(jù)庫增加一個“version”字段來實現(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ù)。樂觀鎖機制避免了長事務(wù)中的數(shù)據(jù)庫加鎖開銷(用戶A和用戶B操作過程中,都沒有對數(shù)據(jù)庫加鎖),大大提升了大并發(fā)量下的系統(tǒng)整體性表現(xiàn)。 Hibernate在其數(shù)據(jù)訪問引擎中內(nèi)置了樂觀鎖實現(xiàn)。需要注意的是,由于樂觀鎖機制是我們的系統(tǒng)中實現(xiàn),來自外部系統(tǒng)的用戶更新操作不受我們系統(tǒng)的控制,因此可能會造成臟數(shù)據(jù)被更新到數(shù)據(jù)庫中。
3、使用悲觀鎖進(jìn)行控制。悲觀鎖大多數(shù)情況下依靠數(shù)據(jù)庫的鎖機制實現(xiàn),如Oracle的select.......for update語句,以保證操作最大程度的獨占性。但隨之而來的就是數(shù)據(jù)庫性能的大量開銷,特別是對長事務(wù)而言,這樣的開銷往往無法承受。如一個金融系統(tǒng),當(dāng)某個操作員讀取用戶的數(shù)據(jù),并在讀出的用戶數(shù)據(jù)的基礎(chǔ)上進(jìn)行修改時(如更改用戶帳戶余額),如果采用悲觀鎖機制,也就意味整個操作過程中(從操作員讀出數(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í)行計劃”對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):獨立訪問使用
數(shù)字越大鎖級別越高, 影響的操作越多。
一般的查詢語句如select ... from ... ;是小于2的鎖, 有時會在v$locked_object出現(xiàn)。
select ... from ... for update; 是2的鎖。
當(dāng)對話使用for update子串打開一個游標(biāo)時,
所有返回集中的數(shù)據(jù)行都將處于行級(Row-X)獨占式鎖定,
其他對象只能查詢這些數(shù)據(jù)行,不能進(jìn)行update、delete或select...for update操作。
insert / update / delete ... ; 是3的鎖。
沒有commit之前插入同樣的一條記錄會沒有反應(yīng),
因為后一個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語句殺掉長期沒有釋放非正常的鎖:
可以用樂觀鎖,在表上面加個字段rowversion,假如初值是1
當(dāng)一個用戶去更新表時,
1)先獲取這個字段的值1
2)然后更新數(shù)據(jù),rowversion+1,
3)提交時,先判斷rowversion是否等于1,
如果不等于,說明有別的用戶已經(jīng)更改過該行數(shù)據(jù)了。就從1)開始在做一遍。
如果等于,就提交(此時rowversion=2)
你可以查查樂觀鎖的相關(guān)知識。
ORACLE鎖具體分為以下幾類:
1.按用戶與系統(tǒng)劃分,可以分為自動鎖與顯示鎖
自動鎖:當(dāng)進(jìn)行一項數(shù)據(jù)庫操作時,缺省情況下,系統(tǒng)自動為此數(shù)據(jù)庫操作獲得所有有必要的
顯示鎖:某些情況下,需要用戶顯示的鎖定數(shù)據(jù)庫操作要用到的數(shù)據(jù),才能使數(shù)據(jù)庫操作執(zhí)行得更好,顯示鎖是用戶為數(shù)據(jù)庫對象設(shè)定的。
2.按鎖級別劃分,可分為共享鎖與排它鎖
共享鎖:共享鎖使一個事務(wù)對特定數(shù)據(jù)庫資源進(jìn)行共享訪問——另一事務(wù)也可對此資源進(jìn)行訪問或獲得相同共享鎖。共享鎖為事務(wù)提供高并發(fā)性,但如拙劣的事務(wù)設(shè)計+共享鎖容易造成死鎖或數(shù)據(jù)更新丟失。
排它鎖:事務(wù)設(shè)置排它鎖后,該事務(wù)單獨獲得此資源,另一事務(wù)不能在此事務(wù)提交之前獲得相同對象的共享鎖或排它鎖。
3.按操作劃分,可分為DML鎖、DDL鎖
+DML鎖又可以分為,行鎖、表鎖、死鎖
-行鎖:當(dāng)事務(wù)執(zhí)行數(shù)據(jù)庫插入、更新、刪除操作時,該事務(wù)自動獲得操作 表中操作行的排它鎖。
-表級鎖:當(dāng)事務(wù)獲得行鎖后,此事務(wù)也將自動獲得該行的表鎖(共享鎖),以防止其它事務(wù)進(jìn)行DDL語句影響記錄行的更新。事務(wù)也可以在進(jìn)行 過程中獲得共享鎖或排它鎖,只有當(dāng)事務(wù)顯示使用LOCK TABLE語 句顯示的定義一個排它鎖時,事務(wù)才會獲得表上的排它鎖,也可使用
LOCK TABLE顯示的定義一個表級的共享鎖(LOCK TABLE具體用法請參 考相關(guān)文檔)。
-死鎖:當(dāng)兩個事務(wù)需要一組有沖突的鎖,而不能將事務(wù)繼續(xù)下去的話,就 出現(xiàn)死鎖。
如事務(wù)1在表A行記錄#3中有一排它鎖,并等待事務(wù)2在表A中記錄#4 中排它鎖的釋放,而事務(wù)2在表A記錄行#4中有一排它鎖,并等待事務(wù) 1在表A中記錄#3中排它鎖的釋放,事務(wù)1與事務(wù)2彼此等待,因此就造 成了死鎖。死鎖一般是因拙劣的事務(wù)設(shè)計而產(chǎn)生。
死鎖只能使用SQL下:alter system kill session 'sid,serial#';
或者使用相關(guān)操作系統(tǒng)kill進(jìn)程的命令,如UNIX下kill -9 sid,或者 使用其它工具殺掉死鎖進(jìn)程。
+DDL鎖又可以分為:排它DDL鎖、共享DDL鎖、分析鎖
-排它DDL鎖:創(chuàng)建、修改、刪除一個數(shù)據(jù)庫對象的DDL語句獲得操作對象的 排它鎖。
如使用alter table語句時,為了維護(hù)數(shù)據(jù)的完成性、一致性、
合法性,該事務(wù)獲得一排它DDL鎖。
-共享DDL鎖:需在數(shù)據(jù)庫對象之間建立相互依賴關(guān)系的DDL語句通常需共享
獲得DDL鎖。
如創(chuàng)建一個包,該包中的過程與函數(shù)引用了不同的數(shù)據(jù)庫表,
當(dāng)編譯此包時,該事務(wù)就獲得了引用表的共享DDL鎖。
-分析鎖:ORACLE使用共享池存儲分析與優(yōu)化過的SQL語句及PL/SQL程序,使
運行相同語句的應(yīng)用速度更快。一個在共享池中緩存的對象獲得
它所引用數(shù)據(jù)庫對象的分析鎖。分析鎖是一種獨特的DDL鎖類型,
ORACLE使用它追蹤共享池對象及它所引用數(shù)據(jù)庫對象之間的依賴 關(guān)系。當(dāng)一個事務(wù)修改或刪除了共享池持有分析鎖的數(shù)據(jù)庫對象
時,ORACLE使共享池中的對象作廢,下次在引用這條SQL/PLSQL語 句時,ORACLE重新分析編譯此語句。
4.內(nèi)部閂鎖
內(nèi)部閂鎖:這是ORACLE中的一種特殊鎖,用于順序訪問內(nèi)部系統(tǒng)結(jié)構(gòu)。
當(dāng)事務(wù)需向緩沖區(qū)寫入信息時,為了使用此塊內(nèi)存區(qū)域, ORACLE首先必須取得這塊內(nèi)存區(qū)域的閂鎖,才能向此塊內(nèi)存寫入
信息。
新聞名稱:oracle如何加樂觀鎖,數(shù)據(jù)庫加樂觀鎖
文章來源:http://vcdvsql.cn/article34/dsiidpe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計、標(biāo)簽優(yōu)化、小程序開發(fā)、域名注冊、手機網(wǎng)站建設(shè)、
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)