oracle事務和鎖

在瞭解oracle鎖之前,先來看下在多用戶併發操作下數據庫可能出現哪些問題?

1、丟失更新

簡單的說當操作按照下面的操作進行時便會發生丟失更新的問題

a、會話session1中的一個事務獲取一行數據,放入本地內存,並展現給最終用戶User1

b、會話session2中的一個事務也獲取該行數據,展現給用戶User2

c、User1修改該行數據的某個字段x,並提交,此時session1中的事務已經執行

d、User2修改該行數據的某個字段y,並提交,session2中的事務也已經執行

按照上面的操作進行c步驟User1所做的更新被d步驟覆蓋,也就是丟失了更新。

此類問題很容易的便會發生,必須由應用的開發人員自己去保證。那麼開發人員需要做哪些事情呢?實際上就是使用某種鎖策略,共有兩種鎖策略:樂觀鎖和悲觀鎖

悲觀鎖:

上面的丟失更新問題,在於查詢和更新之間有其他的事務完成了更新操作,悲觀鎖的策略認爲查詢出來的數據總會被其他的事務修改,因此在查詢的時候使用select for update來獲得鎖定,這樣在更新之前保證不會有其他的事務無更新鎖定的數據,悲觀鎖可能造成死鎖並且需要和oracle之間維護一個長連接。

樂觀鎖:

樂觀鎖假定數據在查出來後不會被其他事務更改,因此在查詢的時候不會鎖定,直到修改的時候纔會去檢測衝突。樂觀鎖的實現方式通常是數據增加版本戳,具體來說就是給表增加一列,可以爲number類型也可以爲timestamp類型。每當更新數據的時候number+1或者更新timestamp爲當前時間,更新的時候對版本戳進行比對,如果不同則說明該條數據已經被更新過,否則說明可以更新。

oracle的多版本控制

oracle多版本控制提供了語句級別的讀一致性,同時可以實現非阻塞讀。

oracle中的語句級一致性可以保證一個事務只能看到查詢開始之前已經提交的事務更改的數據,未提交的事務和查詢開始之後提交的數據不會被查詢到。

做下面的一個實驗來驗證一下

數據準備如下:

----------create table-----------------
create table test (id varchar2(128),name varchar2(128));
-----------insert data-----------------------
insert into test values('1','a');
commit;
--------------delete data----------------------
delete test;
commit;
------------query and sleep 10 seconds---------------------------
set serveroutput on;
declare
  cursor cur is select * from test;
  begin
  for rec in cur
  loop
    dbms_output.put_line(rec.name);
    dbms_lock.sleep(10);--中間等待另外一個session啓動並執行更新數據操作
   end loop;
   end;
/
------------------------------------------

創建test表,然後插入一條數據,開啓兩個plsql,在其中的一個plsql中數據查詢plsql塊如下:


中間讓該操作停頓10s中,然後在另外一個plsql中繼續插入數據並提交,最後可以看到在第一個plsql中只查詢到了一開始我們預置的一條數據,查詢期間其他事務所做的更改沒有被感知到。

但是在同一個事務中所做的更改會被本次事務可見,簡單的一個實驗如下:

插入一條數據,但是不提交,在本次事務中依然可以看到插入的本條數據。


上面是事務的一致性問題

下面講一下最常見的DML lock(數據鎖)

DML語句在執行的一開始會自動的獲取所操作表的表鎖和行鎖。下面以TX表示行鎖,以TM表示表鎖。先來解釋一下這兩個鎖的含義

TX:行鎖,也叫事務鎖,是一種鎖定表中某一行數據的鎖。下面的語句會讓一個事物獲得每一個被修改行的行鎖,instert,update,delete,merge,select ... for update。在事務提交和回滾前,鎖一直存在。獲得行鎖的事務也會自動的獲得對應修改行所在表的表鎖,目的是防止DDL操作帶來的衝突,行鎖只有排他模式。

TM鎖:當出現下面的幾個語句時事務將自動獲取TM鎖,insert,update,delete,merge,select  ... for update。這些DML語句獲取表鎖爲了保留訪問表的權限同時阻止ddl操作帶來的衝突。可以通過lock table 語句明確的獲得一個表鎖。

一個表鎖可以以下面幾種模式被獲取:

。row share lock(RS)行共享,也叫subshare table lock(SS),意思是擁有此鎖的事務已經鎖住了表中的數據行並且試圖去更新他們。RS鎖是限制最少的表鎖,擁有最高的併發度。

。row exclusive lock(RX)行排他,也叫subexclusive table lock(SX),意思是事務已經更新了數據正持有該鎖,RX鎖允許其他的事務在同一張表中執行query,insert,update,delete或者併發的鎖其他行。因此RX鎖允許多個事務在同一張表中同時獲取RX(非同一行數據)或者RS鎖。

。share table lock(S)共享鎖,持有該鎖的事務允許其他事務查詢該表,但是僅在只有一個事務持有該鎖的情況下才允許更新。多個事務可能同時持有該鎖,因此持有某個表的共享鎖的事務不能確保能夠修改該表。

。share row exclusive table lock(SRX)共享行獨佔鎖,也叫share-subexclusive table lock(SSX),一種比共享表鎖更嚴格的鎖。同一時刻只能有一個事務持有某張表的SRX鎖。持有該鎖的事務只允許其他事務查詢,不能更新。

。exclusive table lock(X)獨佔表鎖,表鎖中最嚴格的一種鎖,允許持有該鎖的事務擁有排他寫的權限。同一時刻只能有一個事務持有X鎖。

也可以用下面的語句查詢這兩個鎖的詳細情況:

select * from v$lock_type where type in('TM','TX');

一個事務所持有的鎖有以下幾種:


下面做一個小的實驗看看select *  for update語句會獲取哪種鎖

1、首先執行查詢命令 select * from test for update

2、執行下面的plsql

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 
/
查詢當前鎖的情況,結果如下:


可以看到本次事務中我們鎖定了表Test,鎖的類型爲3,對照上面的lock mode該鎖爲SX。

下面一組操作演示獲取RS鎖的過程

1、執行下面的語句

lock table test in row share mode;
2、執行查看鎖的語句結果如下:


下面這種圖是鎖的矩陣向榮圖


查詢時候的鎖

查詢可以是顯示的比如select語句也可以是隱式的比如大多數的insert,merge,update,delete語句。唯一一個不包含查詢子項的dml語句是帶有values子句的insert語句。查詢的時候是沒有鎖得,因爲查詢語句不會干擾到其他的語句。在oracle中這種不帶for update的查詢語句經常被描述成非阻塞查詢。

nowait

nowait的作用是當發生鎖衝突的時候立馬返回錯誤信息而不是阻塞的等待。

oracle事務

事務的概念:事務可以看作是由對數據庫的若干操作組成的一個單元,這些操作要麼都完成,要麼都取消,從而保證數據滿足一致性的要求。

事務的ACID特性:

原子性( Atomicity):事務中的所有任務都必須執行或者都不執行,不存在部分事務

一致性( Consistency):事務將數據庫從一個一致性狀態帶到另一個一致性狀態

隔離性( Isolation):一個事務所帶來的影響直到該事務提交之前對其他事務來說都是不可見的

持續性( Durability):經過提交的事務所進行的修改是永久性的

 

oracle中的事務可以由多個DML語句組成但只能有一個DDL語句,這是因爲每個DDL語句都會產生依次隱式提交,所以在包含DDL的事務中,DDL語句最好不要放在中間,因爲這會隱式的將一個“邏輯工作單元”劃分成兩個邏輯工作單元。

 

深入的理解ACID中的I,事務的隔離級別簡單理解就是一個事務對數據庫的修改與並行的另外一個事物的隔離級別

最簡單的情況,兩個併發的事務同時操作數據庫表的相同行時,可能產生下面三個問題:

a、髒讀

讀取一個未提交的事務稱爲髒讀。比如事務T1更新了一行記錄,還未提交所做的修改,這個時候T2讀取了更新後的數據,然後T1執行回滾操作,取消剛纔的修改,所以T2所讀取的行就無效,也就是髒數據。

b、不可重複讀

當事務第二次執行同一個查詢的時候,由於另一個事務提交了更新而得到了不同結果的時候就發生了不可重複讀

比如事務T1讀取一行記錄,緊接着事務T2修改了T1剛剛讀取的記錄,然後T1再次查詢,會發現與第一次讀取的記錄不同。

c、幻讀:

如果事務中的一個查詢第二次執行,但返回了滿足條件過濾標準的記錄,就認爲是發生了幻讀。

比如事務T1讀取一條指定where條件的語句,返回結果集。此時事務T2插入一行新記錄,恰好滿足T1的where條件。然後T1使用相同的條件再次查詢,結果集中可以看到T2插入的記錄,這條新紀錄就是幻讀的結果。

 

在SQL92標準中,事務隔離級別分爲四種,分別爲:ReadUncommitted、Read Committed、Read Repeatable、Serializable

隨着隔離級別的提升,事務之間的隔離水平也相應提高,使得數據一致性也就越高。

這幾種隔離級別允許發生的情況如下:

: 可能出現    ×:不會出現

 

髒讀

不可重複讀

幻讀

Read uncommitted

Read committed

×

Repeatable read

×

×

Serializable

×

×

×

 

上述四種隔離級別依次變高

Read uncommitted(未提交讀):一個事務中的會話可以讀取其他事務未提交的更新結果,如果這個事務最後已回滾結束,將會造成讀取的數據是錯誤的。

Read committed(提交讀):一個事務中的會話只能讀取其他事務已經提交的更新結果,但是其他會話可以修該事務中已經讀取的記錄,因此當該事務再一次讀取相同數據時,會出現錯誤的結果。

Read  repeatable(可重複讀):在保證read committed的同時,也保證在一個事務中讀取到的數據在整個事務期間不會被修改,也就是允許對某條數據的重複讀取,但是不允許其他事務向表中添加記錄(有可能出現幻讀)。

Serializable(序列化):在保證read repeatable的同時,也保證該表的數據不會被其他的DML操作修改。限制最爲嚴格,同時效率也最低。

 

Oracle中的隔離級別

Oracle中有Read committedSerializableread-only三種隔離級別,read-only事務只能看到事務開始時提交的修改,不允許執行INSERT、UPDATE、DELETE語句。同時oracle默認的隔離級別爲Readcommited

 

Oracle中的讀一致性:一個查詢所獲得的數據來自同一時間點。

1、語句級別讀一致性

Oracle總是執行語句級別讀一致性。這可以確保單個查詢返回的所有數據來源於單個時間點(查詢開始的時間點)。因而,一個查詢看不到髒數據或者查詢執行期間其他事務提交的任何改變。查詢執行開始後,只有查詢開始之前提交的數據可以被查詢到。查詢不能看到語句開始執行之後提交的任何數據。(舉個例子,假如某個查詢需要獲取特定的數據總共有1W條滿足,假設需要5分鐘,在查詢開始的第三分鐘,有一個事務刪除了某條滿足條件的數據並且已經提交,對於oracle來說最終查到的數據仍然是1W條)

2、事務級別的讀一致性

隔離級別爲SERIALIZABLE和readonly的事務才支持事務級讀一致性,事務中的所有查詢語句(select 、update、delete)只讀取事務開始之前提交的數據。

 

讀數據一致性是相對於髒讀來說的,要了解oracle數據讀一致性的實現方式,需要先了解下面幾個概念

3undo是什麼

a.UNDO表空間用於存放UNDO數據。當執行DML操作時,Oracle會將這些操作的舊數據寫入UNDO段。管理UNDO數據不僅可以使用回滾段,還可以使用UNDO表空間。

b.UNDO數據的作用:當用戶執行DML操作修改數據時,UNDO數據被存放在UNDO段,而新數據則被存放到數據段中,如果事務操作存在問題,就需要回退事務,以取消事物變化。

例如:執行完UPDATE emp SETsal=1000 WHERE empno=7788後,發現應該修改僱員7963的工資,而不是7788.此時應該執行ROLLBACK語句。

c.讀一致性

用戶檢索數據時,ORACLE總是使用戶只能看到被提交過的數據,這是由Oracle自動提供的。當用戶修改數據,但是沒有提交時,另外一個用戶使用select語句查找該值時,該值就是從undo表空間中取得的。

d.事務恢復

事務恢復是例程恢復的一部分,它是由OracleServer自動完成的。如果在數據庫運行過程中出線歷程失敗,那麼當啓動OracleServer時,後臺進程SMON會自動執行例程恢復。執行例程恢復時,Oracle會重做所有未應用的記錄。然後打開數據庫,回退未提交事務。

oracle的多版本用來實現數據的一致性讀,簡單來講就是在undo空間存儲之前的多個版本的數據,並記錄SCN號,每次比較SCN號來獲取想要的版本。這樣即使正在查詢數據也不會阻塞寫操作。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章