oracle事務特性詳解


原子性

事務是一個完整的操作。事務的各步操作是不可分的(原子的);要么都執行,要么都不執行。

-- 創建表
create table account_money
(
  id    number(4) not null,
  name  varchar2(4) not null,
  money number(5,2) not null
)
;
-- 增加一個檢查約束 
alter table account_money
  add constraint CK_money
  check (money>=0);

 

--向張三這個賬號增加數據
insert into ACCOUNT_MONEY (ID, NAME, MONEY)
values (1001, '張三', 500.00);
insert into ACCOUNT_MONEY (ID, NAME, MONEY)
values (1002, '張三', 1.00);

增加后的表如下:

       ID    NAME    MONEY
1    1001    張三    500.00   
2    1002    張三    1.00   

 

以下為oracle事務處理

BEGIN
  --從張三的1001賬戶轉入張三的1002賬戶
  UPDATE account_money a SET a.Money=a.Money-600 WHERE a.Id='1001';
  UPDATE account_money a SET a.Money=a.Money+600 WHERE a.Id='1002';
  COMMIT;--提交事務
EXCEPTION --異常處理
  WHEN OTHERS THEN ROLLBACK;--出現異常就回滾
  Dbms_Output.Put_Line('轉賬異常,轉賬失敗');  

在上述代碼中,因為賬戶設置了檢查約束,當賬戶小於0時,就會出現異常,如果不進行事務異常處理,那么第二條更新語句會被執行。當做了事務異常處理后,當出現異常就會回滾。

image

一致性

在事務操作前后,數據必須處於一致狀態。是一個業務規則約束的范疇。

同樣使用以上的表來做以說明:

DECLARE
  account_a account_money.Money%TYPE;
  account_b account_money.Money%TYPE;
BEGIN
  SELECT a.money INTO account_a FROM account_money a WHERE a.Id='1001'; 
  SELECT a.money INTO account_b FROM account_money a WHERE a.Id='1002'; 
  Dbms_Output.Put_Line('轉賬前A賬戶余額:'||account_a);
  Dbms_Output.Put_Line('轉賬前B賬戶余額:'||account_b);
  Dbms_Output.Put_Line('轉賬前總余額:'||(account_a+account_b));
  UPDATE account_money SET money=money-100 WHERE ID='1001';
  UPDATE account_money SET money=money+100 WHERE ID='1002';
  COMMIT;
  SELECT a.money INTO account_a FROM account_money a WHERE a.Id='1001'; 
  SELECT a.money INTO account_b FROM account_money a WHERE a.Id='1002'; 
  Dbms_Output.Put_Line('轉賬后A賬戶余額:'||account_a);
  Dbms_Output.Put_Line('轉賬后B賬戶余額:'||account_b);
  Dbms_Output.Put_Line('轉賬后總余額:'||(account_a+account_b));
  EXCEPTION
    WHEN OTHERS THEN
      Dbms_Output.Put_Line('轉賬失敗,業務取消');
  SELECT a.money INTO account_a FROM account_money a WHERE a.Id='1001'; 
  SELECT a.money INTO account_b FROM account_money a WHERE a.Id='1002'; 
  Dbms_Output.Put_Line('停止轉賬后A賬戶余額:'||account_a);
  Dbms_Output.Put_Line('停止轉賬后B賬戶余額:'||account_b);
  Dbms_Output.Put_Line('停止轉賬后總余額:'||(account_a+account_b));
END;

 

image

 

執行上段代碼,

執行第一遍:

轉賬前A賬戶余額:500
轉賬前B賬戶余額:1
轉賬前總余額:501
轉賬后A賬戶余額:400
轉賬后B賬戶余額:101
轉賬后總余額:501

image

執行第二遍:

轉賬前A賬戶余額:400
轉賬前B賬戶余額:101
轉賬前總余額:501
轉賬后A賬戶余額:300
轉賬后B賬戶余額:201
轉賬后總余額:501

執行第三遍:

轉賬前A賬戶余額:300
轉賬前B賬戶余額:201
轉賬前總余額:501
轉賬后A賬戶余額:200
轉賬后B賬戶余額:301
轉賬后總余額:501

。。。。。。

當執行第5遍時:A賬戶的余額為0,如果再執行會出現象呢?

轉賬前A賬戶余額:100
轉賬前B賬戶余額:401
轉賬前總余額:501
轉賬后A賬戶余額:0
轉賬后B賬戶余額:501
轉賬后總余額:501

執行第6遍,第7遍…………:

轉賬前A賬戶余額:0
轉賬前B賬戶余額:501
轉賬前總余額:501
轉賬失敗,業務取消
停止轉賬后A賬戶余額:0
停止轉賬后B賬戶余額:501
停止轉賬后總余額:501

 

我們會發現,當我們做事務處理后,總額不會發生變化,當出現異常就不會再執行(或者說回滾)!

 

隔離性

對數據進行修改的所有並發事務是彼此隔離的,這表明事務必須是獨立的,它不是以任何方式依賴於或影響其它事務。

每個事務是獨立的,我們在PL/SQL中新建兩個SQL窗口就以可以做兩個事務處理。

我們還是使用以上表,表內容如下:

       ID    NAME    MONEY
1    1001    張三    0.00
2    1002    張三    501.00

第一個SQL窗口:

image

 

第二個SQL窗口:

輸入:SELECT * FROM account_money;這條查詢語句,我們會發現,第一個SQL窗口沒有執行之前的數據。

image

如果我們也在第二個SQL窗口使用update更新數據會怎么樣呢?

UPDATE account_money SET money=money+300 WHERE ID='1001';
SELECT * FROM account_money;

他會等待第一個SQL窗口提交事務才會有更新結果!

image

這時我們提交第一個SQL窗口的事務,我們會看到,兩個窗口的結果都發生變化。

image

 

我們再提交第二個SQL窗口的事務(在第一個SQL窗口事務沒有提交之前是不能提交第二個窗口的事務的),結果也同上圖!

 

持久性

事務完成后,它對數據庫的修改被永久保存下來。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM