oracle事務特性詳解

原子性

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

-- 建立表
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事務處理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時,就會出現異常,若是不進行事務異常處理,那麼第二條更新語句會被執行。當作了事務異常處理後,當出現異常就會回滾。3d

image

一致性

在事務操做先後,數據必須處於一致狀態。是一個業務規則約束的範疇。blog

一樣使用以上的表來作以說明:事務

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

 

執行上段代碼,ci

執行第一遍:get

轉帳前A帳戶餘額:500
轉帳前B帳戶餘額:1
轉帳前總餘額:501
轉帳後A帳戶餘額:400
轉帳後B帳戶餘額:101
轉帳後總餘額:501
it

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窗口事務沒有提交以前是不能提交第二個窗口的事務的),結果也同上圖!

 

持久性

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

相關文章
相關標籤/搜索