国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

ORACLE鎖機(jī)制以及For update語句

2019-11-09 13:38:43
字體:
供稿:網(wǎng)友
數(shù)據(jù)庫是一個多用戶使用的共享資源。當(dāng)多個用戶并發(fā)地存取數(shù)據(jù)時(shí),在數(shù)據(jù)庫中就會產(chǎn)生多個事務(wù)同時(shí)存取同一數(shù)據(jù)的情況。若對并發(fā)操作不加控制就可能會讀取和存儲不正確的數(shù)據(jù),破壞數(shù)據(jù)庫的一致性。 加鎖是實(shí)現(xiàn)數(shù)據(jù)庫并發(fā)控制的一個非常重要的技術(shù)。當(dāng)事務(wù)在對某個數(shù)據(jù)對象進(jìn)行操作前,先向系統(tǒng)發(fā)出請求,對其加鎖。加鎖后事務(wù)就對該數(shù)據(jù)對象有了一定的控制,在該事務(wù)釋放鎖之前,其他的事務(wù)不能對此數(shù)據(jù)對象進(jìn)行更新操作。 在數(shù)據(jù)庫中有兩種基本的鎖類型:排它鎖(Exclusive Locks,即X鎖)和共享鎖(Share Locks,即S鎖)。當(dāng)數(shù)據(jù)對象被加上排它鎖時(shí),其他的事務(wù)不能對它讀取和修改。加了共享鎖的數(shù)據(jù)對象可以被其他事務(wù)讀取,但不能修改。數(shù)據(jù)庫利用這兩種基本的鎖類型來對數(shù)據(jù)庫的事務(wù)進(jìn)行并發(fā)控制。 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ù)完整性,。在Oracle數(shù)據(jù)庫中,DML鎖主要包括TM鎖和TX鎖,其中TM鎖稱為表級鎖,TX鎖稱為事務(wù)鎖或行級鎖。當(dāng)Oracle執(zhí)行DML語句時(shí),系統(tǒng)自動在所要操作的表上申請TM類型的鎖。當(dāng)TM鎖獲得后,系統(tǒng)再自動申請TX類型的鎖,并將實(shí)際鎖定的數(shù)據(jù)行的鎖標(biāo)志位進(jìn)行置位。這樣在事務(wù)加鎖前檢查TX鎖相容性時(shí)就不用再逐行檢查鎖標(biāo)志,而只需檢查TM鎖模式的相容性即可,大大提高了系統(tǒng)的效率。TM鎖包括了SS、SX、S、X 等多種模式,在數(shù)據(jù)庫中用0-6來表示。不同的SQL操作產(chǎn)生不同類型的TM鎖。在數(shù)據(jù)行上只有X鎖(排他鎖)。在Oracle數(shù)據(jù)庫中,當(dāng)一個事務(wù)首次發(fā)起一個DML語句時(shí)就獲得一個TX鎖,該鎖保持到事務(wù)被提交或回滾。當(dāng)兩個或多個會話在表的同一條記錄上執(zhí)行 DML語句時(shí),第一個會話在該條記錄上加鎖,其他的會話處于等待狀態(tài)。當(dāng)?shù)谝粋€會話提交后,TX鎖被釋放,其他會話才可以加鎖。當(dāng)Oracle數(shù)據(jù)庫發(fā)生TX鎖等待時(shí),如果不及時(shí)處理常常會引起Oracle數(shù)據(jù)庫掛起,或?qū)е滤梨i的發(fā)生,產(chǎn)生ORA-60的錯誤。這些現(xiàn)象都會對實(shí)際應(yīng)用產(chǎn)生極大的危害,如長時(shí)間未響應(yīng),大量事務(wù)失敗等。 悲觀封鎖和樂觀封鎖 一、悲觀封鎖 鎖在用戶修改之前就發(fā)揮作用: Select ..for update(nowait) Select * from tab1 for update 用戶發(fā)出這條命令之后,oracle將會對返回集中的數(shù)據(jù)建立行級封鎖,以防止其他用戶的修改。 如果此時(shí)其他用戶對上面返回結(jié)果集的數(shù)據(jù)進(jìn)行dml或ddl操作都會返回一個錯誤信息或發(fā)生阻塞。 1:對返回結(jié)果集進(jìn)行update或delete操作會發(fā)生阻塞。 2:對該表進(jìn)行ddl操作將會報(bào):Ora-00054:resource busy and acquire with nowait specified. 原因分析 此時(shí)Oracle已經(jīng)對返回的結(jié)果集上加了排它的行級鎖,所有其他對這些數(shù)據(jù)進(jìn)行的修改或刪除操作都必須等待這個鎖的釋放,產(chǎn)生的外在現(xiàn)象就是其他的操作將發(fā)生阻塞,這個這個操作commit或rollback. 同樣這個查詢的事務(wù)將會對該表加表級鎖,不允許對該表的任何ddl操作,否則將會報(bào)出ora-00054錯誤::resource busy and acquire with nowait specified. 二、樂觀封鎖 樂觀的認(rèn)為數(shù)據(jù)在select出來到update進(jìn)取并提交的這段時(shí)間數(shù)據(jù)不會被更改。這里面有一種潛在的危險(xiǎn)就是由于被選出的結(jié)果集并沒有被鎖定,是存在一種可能被其他用戶更改的可能。因此Oracle仍然建議是用悲觀封鎖,因?yàn)檫@樣會更安全。 阻塞 定義: 當(dāng)一個會話保持另一個會話正在請求的資源上的鎖定時(shí),就會發(fā)生阻塞。被阻塞的會話將一直掛起,直到持有鎖的會話放棄鎖定的資源為止。4個常見的dml語句會產(chǎn)生阻塞 INSERT UPDATE DELETE SELECT…FOR UPDATE INSERT Insert發(fā)生阻塞的唯一情況就是用戶擁有一個建有主鍵約束的表。當(dāng)2個的會話同時(shí)試圖向表中插入相同的數(shù)據(jù)時(shí),其中的一個會話將被阻塞,直到另外一個會話提交或會滾。一個會話提交時(shí),另一個會話將收到主鍵重復(fù)的錯誤。回滾時(shí),被阻塞的會話將繼續(xù)執(zhí)行。 UPDATE 和DELETE當(dāng)執(zhí)行Update和delete操作的數(shù)據(jù)行已經(jīng)被另外的會話鎖定時(shí),將會發(fā)生阻塞,直到另一個會話提交或會滾。 Select …for update 當(dāng)一個用戶發(fā)出select..for update的錯作準(zhǔn)備對返回的結(jié)果集進(jìn)行修改時(shí),如果結(jié)果集已經(jīng)被另一個會話鎖定,就是發(fā)生阻塞。需要等另一個會話結(jié)束之后才可繼續(xù)執(zhí)行。可以通過發(fā)出 select… for update nowait的語句來避免發(fā)生阻塞,如果資源已經(jīng)被另一個會話鎖定,則會返回以下錯誤:Ora-00054:resource busy and acquire with nowait specified. 死鎖-deadlock 定義:當(dāng)兩個用戶希望持有對方的資源時(shí)就會發(fā)生死鎖. 即兩個用戶互相等待對方釋放資源時(shí),oracle認(rèn)定為產(chǎn)生了死鎖,在這種情況下,將以犧牲一個用戶作為代價(jià),另一個用戶繼續(xù)執(zhí)行,犧牲的用戶的事務(wù)將回滾. 例子: 1:用戶1對A表進(jìn)行Update,沒有提交。 2:用戶2對B表進(jìn)行Update,沒有提交。 此時(shí)雙反不存在資源共享的問題。 3:如果用戶2此時(shí)對A表作update,則會發(fā)生阻塞,需要等到用戶一的事物結(jié)束。 4:如果此時(shí)用戶1又對B表作update,則產(chǎn)生死鎖。此時(shí)Oracle會選擇其中一個用戶進(jìn)行會滾,使另一個用戶繼續(xù)執(zhí)行操作。 起因: Oracle的死鎖問題實(shí)際上很少見,如果發(fā)生,基本上都是不正確的程序設(shè)計(jì)造成的,經(jīng)過調(diào)整后,基本上都會避免死鎖的發(fā)生。 DML鎖分類表 表1Oracle的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 oracle 鎖問題的解決 可以用Spotlight軟件對數(shù)據(jù)庫的運(yùn)行狀態(tài)進(jìn)行監(jiān)控。 當(dāng)出現(xiàn)session鎖時(shí),我們要及時(shí)進(jìn)行處理. 1. 查看哪些session鎖: SQL語句:select 'alter system kill session '''||sid||','||serial#||''';' from v$session where sid in (select sid from v$lock where block = 1); SQL> select 'alter system kill session '''||sid||','||serial#||''';' from v$session where sid in (select sid from v$lock where block = 1); 'ALTERSYSTEMKILLSESSION'''||SID||','||SERIAL#||''';' -------------------------------------------------------------------------------- alter system kill session '132,731'; alter system kill session '275,15205'; alter system kill session '308,206'; alter system kill session '407,3510'; 2. 查看session鎖. sql語句:select s.sid, q.sql_text from v$sqltext q, v$session s where q.address = s.sql_address and s.sid = &sid order by piece; SQL> select s.sid,q.sql_text from v$sqltext q, v$session s where q.address = s.sql_address and s.sid in (select sid from v$lock where block = 1) order by piece; SID SQL_TEXT ---------- ---------------------------------------------------------------- 77 UPDATE PROFILE_USER SET ID=1,COMPANY_ID=2,CUSTOMER_ID=3,NAMED 77 _INSURED_ID=4,LOGIN=5,ROLE_ID=6,PASSWord=7,EMAIL=8,TIME_ZON 77 E=9 WHERE PROFILE_USER.ID=:34 3 rows selected. 3. kill鎖的進(jìn)程. SQL語句:alter system kill session '77,22198'; SQL> alter system kill session '391,48398'; 

System altered. 

對for update的使用

 

在日常中,我們對for update的使用還是比較普遍的,特別是在如pl/sql developer中手工修改數(shù)據(jù)。此時(shí)只是覺得方便,而對for update真正的含義缺乏理解。

 

For update是Oracle提供的手工提高鎖級別和范圍的特例語句。Oracle的鎖機(jī)制是目前各類型數(shù)據(jù)庫鎖機(jī)制中比較優(yōu)秀的。所以,Oracle認(rèn)為一般不需要用戶和應(yīng)用直接進(jìn)行鎖的控制和提升。甚至認(rèn)為死鎖這類鎖相關(guān)問題的出現(xiàn)場景,大都與手工提升鎖有關(guān)。所以,Oracle并不推薦使用for update作為日常開發(fā)使用。而且,在平時(shí)開發(fā)和運(yùn)維中,使用了for update卻忘記提交,會引起很多鎖表故障。

 

那么,什么時(shí)候需要使用for update?就是那些需要業(yè)務(wù)層面數(shù)據(jù)獨(dú)占時(shí),可以考慮使用for update。場景上,比如火車票訂票,在屏幕上顯示郵票,而真正進(jìn)行出票時(shí),需要重新確定一下這個數(shù)據(jù)沒有被其他客戶端修改。所以,在這個確認(rèn)過程中,可以使用for update。這是統(tǒng)一的解決方案方案問題,需要前期有所準(zhǔn)備

Select …forupdate語句是我們經(jīng)常使用手工加鎖語句。通常情況下,select語句是不會對數(shù)據(jù)加鎖,妨礙影響其他的DML和DDL操作。同時(shí),在多版本一致讀機(jī)制的支持下,select語句也不會被其他類型語句所阻礙。

 

借助for update子句,我們可以在應(yīng)用程序的層面手工實(shí)現(xiàn)數(shù)據(jù)加鎖保護(hù)操作。本篇我們就來介紹一下這個子句的用法和功能。

 

下面是采自Oracle官方文檔《SQLLanguage Reference》中關(guān)于for update子句的說明:(請雙擊點(diǎn)開圖片查看)

 

 

從for update子句的語法狀態(tài)圖中,我們可以看出該子句分為兩個部分:加鎖范圍子句和加鎖行為子句。下面我們分別針對兩個方面的進(jìn)行介紹。

 

加鎖范圍子句

 

在select…for update之后,可以使用of子句選擇對select的特定數(shù)據(jù)表進(jìn)行加鎖操作。默認(rèn)情況下,不使用of子句表示在select所有的數(shù)據(jù)表中加鎖。

 

//采用默認(rèn)格式for update

SQL> select * from emp where rownum<2 for update;

 

EMPNO ENAME     JOB        MGR HIREDATE         SAL     COMM DEPTNO

----- ---------- --------- ----- ----------- --------- --------- ------

 7369 SMITH     CLERK     79021980-12-17    800.00              20

 

 

此時(shí),我們觀察v$lock和v$locked_object視圖,可以看到鎖信息。

//事務(wù)信息視圖

SQL> select addr,xidusn,xidslot,xidsqn from v$transaction;

 

ADDR        XIDUSN   XIDSLOT    XIDSQN

-------- ---------- ---------- ----------

377DB5D0         7        19       808

//鎖對象信息

SQL> select xidusn,xidslot,xidsqn,object_id,session_id, oracle_username from v$locked_object;

 

   XIDUSN   XIDSLOT    XIDSQN OBJECT_ID SESSION_ID ORACLE_USERNAME

---------- ---------- ---------- ---------- ---------- ------------------------------

        7        19       808     73181        36 SCOTT

//

SQL> select owner,object_name from dba_objects where object_id=73181;

 

OWNER                         OBJECT_NAME

------------------------------ ------------------------------------------------------------

SCOTT                         EMP

 

//

SQL> select addr, sid, type, id1,id2,lmode, request, block from v$lock where sid=36;

 

ADDR     SID TYPE       ID1       ID2     LMODE   REQUEST BLOCK

-------- ---------- ---- ---------- ---------- ---------- ---------- ----------

37E808F0   36 AE         100         0         4         0   0

B7DE8A44  36 TM       73181         0         3         0  0

377DB5D0  36 TX      458771       808         6         0   0

 

 

從上面的情況看,默認(rèn)情況下的for update語句,效果相當(dāng)于啟動了一個會話級別的事務(wù),在對應(yīng)的數(shù)據(jù)表(select所涉及的所有數(shù)據(jù)表)上加入一個數(shù)據(jù)表級共享鎖(TM,lmode=3)。同時(shí),在對應(yīng)的數(shù)據(jù)行中加入獨(dú)占鎖(TX,lmode=6)。

 

根據(jù)我們以前的知識,如果此時(shí)有另一個會話視圖獲取對應(yīng)數(shù)據(jù)行的獨(dú)占權(quán)限(無論是用update/delete還是另一個for update),都會以block而告終。

 

SQL> select sid from v$mystat where rownum<2;

 

      SID

----------

       37

 

SQL> select * from emp where empno=7369 for update;

 

//系統(tǒng)blocking

 

此時(shí)系統(tǒng)中狀態(tài),切換到另一個用戶下進(jìn)行觀察:

 

SQL> select addr, sid, type, id1,id2,lmode, request, block from v$lock where sid in (36,37);

 

ADDR  SID TYPE       ID1       ID2     LMODE   REQUEST     BLOCK

-------- ---------- ---- ---------- ---------- ---------- ---------- ----------

37E808F0        36 AE         100         0         4         0  0

37E80ED4        37 AE         100         0         4         0  0

37E80F48        37 TX      458771       808         0         6  0

B7DE8A44        37 TM       73181         0         3         0 0

B7DE8A44        36 TM       73181         0         3         0 0

377DB5D0        36 TX      458771       808         6         0 1

 

6 rows selected

 

SQL> select * from dba_waiters;

 

WAITING_SESSION HOLDING_SESSION LOCK_TYPE                 MODE_HELD                               MODE_REQUESTED                            LOCK_ID1  LOCK_ID2

--------------- --------------- -------------------------- ---------------------------------------- ---------------------------------------- ---------- ----------

            37             36Transaction               Exclusive                               Exclusive                                   458771       808

 

 

由此,我們可以獲取到結(jié)論:for update子句的默認(rèn)行為就是自動啟動一個事務(wù),借助事務(wù)的鎖機(jī)制將數(shù)據(jù)進(jìn)行鎖定。

 

 

Of子句是配合for update語句使用的一個范圍說明標(biāo)記。從官方的語法結(jié)構(gòu)看,后面可以跟一個或者多個數(shù)據(jù)列列表。這種語法場景常常使用在進(jìn)行連接查詢的select中,對其中一張數(shù)據(jù)表數(shù)據(jù)進(jìn)行鎖定。

 

SQL> select empno,ename,job,mgr,sal from emp,dept where emp.deptno=dept.deptno and empno=7369 for update of emp.empno;

 

EMPNO ENAME     JOB        MGR      SAL

----- ---------- --------- ----- ---------

 7369 SMITH     CLERK     7902   800.00

 

SQL> select addr, sid, type, id1,id2,lmode, request, block from v$lock where sid=36;

 

ADDR      SID TYPE       ID1       ID2     LMODE   REQUEST BLOCK

-------- ---------- ---- ---------- ---------- ---------- ---------- ----------

37E808F0        36 AE         100         0         4         0   0

B7E1C2E8        36 TM       73181         0         3        0   0

377DBC0C        36 TX       65566       747         6      0  0

 

 

上面的語句中,我們看到使用for update of指定數(shù)據(jù)列之后,鎖定的范圍限制在了所在的數(shù)據(jù)表。也就是說,當(dāng)我們使用連接查詢配合of子句的時(shí)候,可以實(shí)現(xiàn)有針對性的鎖定。

 

同樣在連接查詢的時(shí)候,如果沒有of子句,同樣采用默認(rèn)的模式,會如何呢?

 

SQL> select empno,ename,job,mgr,sal from emp,dept where emp.deptno=dept.deptno and empno=7369 for update;

 

EMPNO ENAME     JOB        MGR      SAL

----- ---------- --------- ----- ---------

 7369 SMITH     CLERK     7902   800.00

 

SQL> select addr, sid, type, id1,id2,lmode, request, block from v$lock where sid=36;

 

ADDR    SID TYPE       ID1       ID2     LMODE   REQUEST BLOCK

-------- ---------- ---- ---------- ---------- ---------- ---------- ----------

37E808F0        36 AE         100         0         4         0    0

B7E1C2E8        36 TM       73179         0         3         0  0

B7E1C2E8        36 TM       73181         0         3         0    0

377DBC0C        36 TX      458777       805         6         0   0

 

SQL> select owner,object_name from dba_objects where object_id=73179;

 

OWNER                         OBJECT_NAME

------------------------------ --------------------------------------------------------------------------------

SCOTT                         DEPT

 

 

明顯可以看到,當(dāng)我們沒有使用of子句的時(shí)候,默認(rèn)就是對所有select的數(shù)據(jù)表進(jìn)行l(wèi)ock操作。

 

 

加鎖行為子句

 

加鎖行為子句相對比較容易理解。這里分別介紹。

 

Nowait子句

 

當(dāng)我們進(jìn)行for update的操作時(shí),與普通select存在很大不同。一般select是不需要考慮數(shù)據(jù)是否被鎖定,最多根據(jù)多版本一致讀的特性讀取之前的版本。加入for update之后,Oracle就要求啟動一個新事務(wù),嘗試對數(shù)據(jù)進(jìn)行加鎖。如果當(dāng)前已經(jīng)被加鎖,默認(rèn)的行為必然是block等待。

 

使用nowait子句的作用就是避免進(jìn)行等待,當(dāng)發(fā)現(xiàn)請求加鎖資源被鎖定未釋放的時(shí)候,直接報(bào)錯返回。

///session1中

SQL> select * from emp for update;

 

EMPNO ENAME     JOB        MGR HIREDATE         SAL     COMM DEPTNO

----- ---------- --------- ----- ----------- --------- --------- ------

 7369 SMITH     CLERK     79021980-12-17    800.00              20

 7499 ALLEN     SALESMAN  76981981-2-20    1600.00   300.00    30

 7521 WARD      SALESMAN  76981981-2-22    1250.00   500.00    30

 7566 JONES     MANAGER   78391981-4-2     2975.00              20

 

//變換session,進(jìn)行執(zhí)行。

SQL> select * from emp for update nowait;

 

select * from emp for update nowait

 

ORA-00054:資源正忙,但指定以NOWAIT方式獲取資源,或者超時(shí)失效

 

 

對應(yīng)的還有就是wait子句,也就是默認(rèn)的for update行為。一旦發(fā)現(xiàn)對應(yīng)資源被鎖定,就等待blocking,直到資源被釋放或者用戶強(qiáng)制終止命令。

 

 

對wait子句還存在一個數(shù)據(jù)參數(shù)位,表示當(dāng)出現(xiàn)blocking等待的時(shí)候最多等待多長時(shí)間。單位是秒級別。

//接上面的案例

SQL> select * from emp for update wait 3;

 

select * from emp for update wait 3

 

ORA-30006:資源已被占用;執(zhí)行操作時(shí)出現(xiàn)WAIT超時(shí)

 

 

 

Skip locked參數(shù)

 

Skip locked參數(shù)是最新引入到for update語句中的一個參數(shù)。簡單的說,就是在對數(shù)據(jù)行進(jìn)行加鎖操作時(shí),如果發(fā)現(xiàn)數(shù)據(jù)行被鎖定,就跳過處理。這樣for update就只針對未加鎖的數(shù)據(jù)行進(jìn)行處理加鎖。

 

//session1中,對一部分?jǐn)?shù)據(jù)加鎖;

SQL> select * from emp where rownum<4 for update;

 

EMPNO ENAME     JOB        MGR HIREDATE         SAL     COMM DEPTNO

----- ---------- --------- ----- ----------- --------- --------- ------

 7369 SMITH     CLERK     79021980-12-17    800.00              20

 7499 ALLEN     SALESMAN  76981981-2-20    1600.00   300.00    30

 7521 WARD      SALESMAN  76981981-2-22    1250.00   500.00    30

 

//在session2中;

SQL> select * from emp for update skip locked;

 

EMPNO ENAME     JOB        MGR HIREDATE         SAL     COMM DEPTNO

----- ---------- --------- ----- ----------- --------- --------- ------

(篇幅原因,省略)

7934 MILLER    CLERK     77821982-1-23    1300.00              10

 

11 rows selected

 

 

總數(shù)據(jù)一共14行。Session1中,先lock住了3行數(shù)據(jù)。之后的seesion2中,由于使用的skip locked子句參數(shù),將剩下的11條數(shù)據(jù)進(jìn)行讀取到并且加鎖。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 公安县| 麻城市| 桂阳县| 郧西县| 巴青县| 卢龙县| 汉寿县| 鄂尔多斯市| 大新县| 安龙县| 连州市| 曲阳县| 平陆县| 香港 | 鹤峰县| 商水县| 团风县| 乐清市| 黄浦区| 乌拉特前旗| 榆中县| 中江县| 长丰县| 育儿| 兴义市| 九台市| 济南市| 察雅县| 论坛| 沁阳市| 高州市| 上林县| 湖南省| 封开县| 宿松县| 龙江县| 荃湾区| 乡宁县| 象州县| 文山县| 卢湾区|