Oracle 事務 鎖

1、 事務

是一系列的數據庫操做,是數據庫應用的基本邏輯單位以及併發控制的基本單位。所謂的事務,它是一個操做序列,這些操做要麼都執行,要麼都不執行,它是一個不可分割的工做單位。數據庫

要將有組語句做爲事務考慮,就須要經過ACID測試,即原子性,一致性,隔離性和持久性。session

1. 事務性質

原子性、一致性或可串性、隔離性、持久性併發

▶ 原子性Atomic:即不可分割性,事務要麼所有被執行,要麼就所有不被執行。oracle

▶ 一致性或可串性Consistency:事務的執行使得數據庫從一種正確狀態轉換成另外一種正確狀態。ide

▶隔離性Isolation:事務容許多個用戶對同一個數據進行併發訪問,而不破壞數據的正確性和完整性。同時,並行事務的修改必須與其餘並行事務的修改相互獨立。在事務正確提交以前,不容許把該事務對數據的任何改變提供給任何其餘事測試

▶ 持久性Durability:事務正確提交後,其結果將永久保存在數據庫中,即便在事務提交後有了其餘故障,事務的處理結果也會獲得保存。ui

2. 事務語句

▶ 開始事物:begin transactionspa

▶ 提交事物:commit transaction3d

▶ 回滾事務:rollback transactionrest

用戶在事務(transaction)內能夠聲明(declare)被稱爲保存點(savepoint)的標記。保存點將一個大事務劃分爲較小的片段。

▶ save transaction 保存點名稱 --自定義保存點的名稱和位置

▶ rollback transaction 保存點名稱 --回滾到自定義的保存點

用戶可使用保存點(savepoint)在事務(transaction)內的任意位置做標記。以後用戶在對事務進行回滾操做(rolling back)時,就能夠選擇從當前執行位置回滾到事務內的任意一個保存點。

3. 事務使用

① 建立一張表以做示例

 1 -- 建表
 2   
 3 create table student(
 4 id varchar2(4),
 5 name varchar2(100), --姓名
 6 sex varchar2(1),  --性別 1 男  2 女  0 未知
 7 score integer default 0
 8 );
 9 
10 select * from student;
11 
12 -- 插入數據
13 
14 insert into student (id, name, sex)values ('0001', '大王', '2'); 
15 insert into student (id, name, sex)values ('0002', '劉一', '1'); 
16 insert into student (id, name, sex)values ('0003', '陳二', '2');
17 insert into student (id, name, sex)values ('0004', '張三', '0');
18 insert into student (id, name, sex)values ('0005', '李四', '1');
19 insert into student (id, name, sex)values ('0006', '王五', '0');
20 insert into student (id, name, sex)values ('0007', '趙六', '1');
21 insert into student (id, name, sex)values ('0008', '孫七', '2');
22 insert into student (id, name, sex)values ('0009', '周八', '2');
23 insert into student (id, name, sex)values ('0010', '吳九', '1');
24 insert into student (id, name, sex)values ('0011', '鄭十', '1');
25 commit;
View Code

 

② 以上表爲基礎的一個事務示例

 1 CREATE OR REPLACE PROCEDURE p_transaction_test(p_error_no   out int, --錯誤編號
 2                                                p_error_info out varchar2 --錯誤信息
 3                                                ) as
 4 
 5 begin
 6   /*
 7   wangrui 事務commit測試
 8   ①處commit:第一條更新成功,第二條更新失敗,回滾;因爲第二條失敗時,第一條已經提交。
 9   ②處commit;第一條更新失敗,第二條更新失敗;因爲沒有提交,第二條失敗,語句還沒到②commit處已經回滾,兩條均未更新。
10   ③處commit;在此,跟②處的結果是同樣的,是對事物最後的提交。
11   
12   Ⅰ處savepoint會使事務回滾到A爲止,若是此時①處有commit,會致使Ⅰ保存點失效,報錯,可是事務會回滾到①提交處
13   Ⅱ處savepoint會使事務回滾到B位置
14   注意:roll rollback to savepoint以後須要commit。不然事務回到savepoint以後,savepoint以前的得到的鎖並未被釋放
15   
16   通常使用commit提交便可,不使用savepoint。
17   ……
18   */
19 
20   p_error_no   := 0;
21   p_error_info := ' ';
22   begin
23   
24     --
25     --savepoint save1;
26   
27     update student set sex = '1' where id = '0001'; --一條會成功更新的SQL語句
28   
29     --
30     commit;
31     --
32     --savepoint save1;
33   
34     update student set sex = '11' where id = '0002'; --一條語句超長,更新失敗的SQL語句
35   
36     --
37     --commit;
38   
39   exception
40     when others then
41       rollback --to savepoint save1;commit
42       ;
43       p_error_no   := -1;
44       p_error_info := '失敗:' || SQLERRM;
45       return;
46   end;
47 
48   --③提交事務
49   commit;
50 
51 end;
View Code

 

2、 事務的隔離級別

1. 事務併發訪問時存在的問題

▶ 髒讀:若是一個事務讀取的記錄是另外一個未完成事務的一部分,就發生了髒讀。若是第一個事務正常完成,就沒有什麼問題。可是,若是前一個事務回滾了,那將從數據庫從未發生的事務中獲取了信息。

▶ 不可重複讀取:很容易將不可重複性讀取和髒讀混淆。若是一個事務中兩次讀取記錄,而另外一個事務在這期間改變了數據,就會發生不可重複性讀取。

▶ 幻讀:若是一個事務讀取一個記錄,返回結果集,此時,另外一個事務插入一條記錄並提交

2. 事務的隔離級別 

3. ORACLE支持的事務隔離級別

只讀模式:只讀事務只能看到事務執行前就已經提交的數據,且事務中不能執執行 INSERT , UPDATE ,及 DELETE 語句

已提交讀取:Oracle 默認使用的事務隔離級別。事務內執行的查詢只能看到查詢執行前(而非事務開始前)就已經提交的數據。Oracle 的查詢永遠不會讀取髒數據(未提交的數據)。

Oracle 不會阻止一個事務修改另外一事務中的查詢正在訪問的數據,所以在一個事務內的兩個查詢的執行間歇期間,數據有可能被其餘事務修改。舉例來講,若是一個事務內同一查詢執行兩次,可能會遇到不可重複讀取或不存在讀取的現象。 

串行化:串行化隔離的事務只能看到事務執行前就已經提交的數據,以及事務內 INSERT , UPDATE ,及 DELETE 語句對數據的修改。串行化隔離的事務不會出現不可重複讀取或不存在讀取的現象。

1 --只容許select操做,不容許有任何修改數據庫(包括 insert、update、delete)中數據的操做語句,容許建立語句create
2 set transaction read only;
3 --默認設置,表示在事務中能夠有訪問語句、修改語句(包括insert、delete、update),容許建立語句create,同read committed
4 set transaction read  write; 
5 --同read write; 
6 set transaction isolation level read committed;
7 --serialzable能夠執行DML操做
8 set transaction isolation level serializable;

3.1 read only 

新建一個事務以下

set transaction read only;

① 執行

select * from student;

 

② 執行

update student set score = 100 where id = '0002';

 

3.2 read write

① 新建一個事務以下

set transaction read write;

② 執行

select * from student;

 

② 執行

update student set score = 100 where id = '0002';

select * from  student;

 

結論:容許讀寫(包括insert、delete、update)

3.3 isolation level read committed(可幻讀和重複讀)

新建兩個事務以下

① 新建事務T1

set transaction read  write;

select * from student;

 

② 新建事務T2

set transaction isolation level read committed;

select * from student;

 

③ 在事務T1中修改ID=002的記錄並commit;

update student set score = 100 where id = '0002';--未commit狀態下在T2事務中並未看到更新

commit;

④ 在事務T2 中查看commit後的結果以下(commit狀態下看到更新結果)

select * from student;

 

⑤ 在事務T1中刪除ID=003的記錄, 並commit;

delete from student where id='0003';--未commit時在T2中還能夠看到該條記錄

commit;

⑥ 在事務T2 中查看commit後的結果以下(commit以後看不到該條記錄)

 

⑦ 在事務T1中插入ID=0006的記錄,並commit;

insert into student (id, name, sex)values ('0006', '王五', '0');--未commit以前在T2中看不到該條記錄

commit;

⑧ 在事務T2 中查看commit後的結果以下(commit以後看到該條記錄已經添加)

 

結論:①-⑥ 說明事務隔離級別爲isolation level read committed時,容許可重複讀。

⑦-⑧ 說明事務隔離級別爲 isolation level read committed, 容許幻想讀

3.4  isolation level  serializable

建立了兩個事務以下

① 新建事務T1

set transaction read write;

select * from student;

 

② 新建事務T2

set transaction isolation level serializable;

select * from student;

 

③ 在事務T1中修改ID=002的記錄並commit;

update student set score = 100 where id = '0002';--未commit狀態下在T2事務中並未看到更新

commit;

④ 在在事務T2 中查看commit後的結果以下(commit狀態下也沒有看到更新)

 

⑤ 在事務T1中刪除ID=003的記錄, 並commit;

delete  from student where id='0003';--未commit時在T2中還能夠看到該條記錄

commit;

⑥ 在事務T2 中查看commit後的結果以下(commit狀態下依然能夠看到該條記錄)

 

⑦ 在事務T1中插入ID=0006的記錄,並commit;

insert into student (id, name, sex)values ('0006', '王五', '0');--未commit以前在T2中看不到該條記錄

commit;

⑧ 在事務T2 中查看commit後的結果以下(commit狀態下依然看不到該條記錄)

 

結論:①-⑥ 說明事務隔離級別爲isolation level  serializable時,不支持可重複讀。

⑦-⑧ 說明事務隔離級別爲 isolation level  serializable 時, 不支持幻想讀

3、 鎖

鎖是一種機制,多個事務同時訪問一個數據庫對象時,該機制能夠實現對併發的控制

ORCLE 多事務併發可能存在的問題

丟失更新:丟失更新發生在一個更新成功寫入數據庫後,而又意外地被另外一個事務重寫時。這是怎麼發生的呢?若是有兩個事務讀取整個記錄,而後其中一個向記錄寫入了更新信息,而另外一個事務也向該記錄寫入更新信息,這是就會出現丟失更新。

1. oracle 中鎖的類型

① DML鎖(data locks,數據鎖),用於保護數據的完整性。oracle自動的施加和釋放。

② DDL鎖(dictionary locks,字典鎖),用於保護數據庫對象的結構,如表、索引等的結構定義. 事務開始時施加,使用Commit後者Rollback被釋放。

③ 內部鎖和閂(internal locks and latches),保護數據庫的內部結構。由oracle本身管理以保護內部數據庫結構。

2. 鎖的粒度

① 行級鎖(TX):阻止該行上的DML操做,直到Commit或者Rollback。

② 表級鎖(TM):

③ 數據庫級鎖::

eg:將數據庫鎖定爲只讀模式 alter database open read only;

eg:將數據庫設置爲限制模式(導入導出數據庫時使用):alter system enable restricted session;

3. oracle 中鎖的模式

3.1 鎖的模式

 

3.2 鎖的兼容性

3.3 鎖表語句

1 lock table student in row share mode;
2 lock table student in row exclusive mode;  --用於行的修改
3 lock table student in share mode;   --阻止其餘DML操做
4 lock table student in share row exclusive mode;    --阻止其餘事務操做
5 lock table student in exclusive mode;  --獨立訪問使用

 

4. 鎖的查看

① 建立一個事務,執行

update student set score=888 WHERE ID='0004';

② 執行

select * from v$locked_object; --object_id爲表名

 

③ 執行

1 select s.sid, s.serial#, s.username, s.schemaname, s.osuser, s.process, s.machine, s.terminal, s.logon_time, l.type, l.lmode
2   from v$session s, v$lock l
3  where s.sid = l.sid
4    and s.sid= '3231'
5  order by sid;

 

如圖,DML操做,得到一個TM鎖,還得到一個TX鎖,還有一個……,故而其餘事務能夠對該表的其餘行進行編輯,可是0004行不容許其餘事務有任何操做。

咱們能夠認爲Oracle 6種MODE的鎖,根據鎖定的對象不一樣而有不一樣的名稱,如6號的X鎖,既能夠是用於鎖表的TM鎖,也能夠是TX鎖,也能夠是DDL鎖。

4、 死鎖

若是一個鎖因爲另外一個鎖佔有資源而不能完成應該作的工做,就會致使死鎖;反之亦然。

1 死鎖產生條件

① Mutual exclusion(互斥):資源不能被共享,只能由一個進程使用。

② Hold and wait(請求並保持):已經獲得資源的進程能夠再次申請新的資源。

③ No pre-emption(不可剝奪):已經分配的資源不能從相應的進程中被強制地剝奪。

④ Circular wait(循環等待條件):系統中若干進程組成環路,該環路中每一個進程都在等待相鄰進程正佔用的資源。

2. 死鎖模擬

① 查看錶內容

select * from student;

 

② 新建一個事務T1,執行

update student set score=111 WHERE ID='0002';

未提交狀態下提示一行被更新

③ 新建一個事務T2,執行

update student set score=333 WHERE ID='0003';

未提交狀態下提示一行被更新

④ 在事務T1中執行

update student set score=222 WHERE ID='0003';

顯示「正在執行……」表示等待中

⑤ 在事務T2中執行

update student set score=444 WHERE ID='0002';

 

此時,事務T2顯示「正在執行……」表示等待,T1事務是提交或者回滾狀態

⑥ commit 事務T1

 

顯示事務T1只更新了0002,0003並未更新成功。

⑦ commit 事務T2,而後查看結果

 

顯示事務T2更新了0002,0003,至關於事務T1的結果丟失了。

3. 解決死鎖衝突

在沒有執行⑥⑦操做的狀況下

新⑥ 執行

select sid,serial#,username from v$session where sid in (select blocking_session from v$session);

alter system kill session '1522,42255';

第一行代碼找到sid='1522,serial#=42255'

第二行代碼殺掉這個堵塞的進程

新⑦ 此時,提交進程事務T1,結果顯示。

 

新⑧ 提交事務T2,顯示提交成功,查看結果

 

顯示事務T2更新了0002,0003,至關於事務T1的結果丟失了。

結論:oracle在死鎖狀況下,會保存後面一個事務的更新結果。

4. 事務和死鎖預防總結

① 避免應用不運行長事務。

② 常常提交以免長時間鎖定行。

③ 避免使用LOCK命令鎖定表。

⑤ 在高峯期間執行DDL操做,在非高峯期間執行長時間運行的查詢或事務。

相關文章
相關標籤/搜索