事務:
一種機制,一個操作序列,是數據庫工作的邏輯單元
一個或者多個完成一組相關行為的SQL語句組成
一個不可分割的工作邏輯單元
事務的概念:
一個不可分割的工作邏輯單元,
保證數據庫的完整性
事務的特性:簡稱ACID屬性
原子性:(Atomicity): 事務是一個完整的操作,事務的各步操作是不可分的(原子的),要么都執行,要么都不執行
一致性(Consistency):在事務操作前后,數據必須處於一致狀態
隔離性(Isolation): 對數據進行修改的所有並發事務是彼此隔離的,這表明事務必須是獨立的,它不應以任何方式依賴於或影響其他事務
持久性(Durability):事務完成后,它對數據庫的悠被永久保持
創建一張表:
CREATE TABLE acc( ID NUMBER(19), NAME VARCHAR2(20) NOT NULL, bal NUMBER(19,3) NOT NULL, CONSTRAINT pd_id PRIMARY KEY(ID), CONSTRAINT ck_bal CHECK(bal>=0) ); SELECT * FROM acc; INSERT INTO acc VALUES(1001,'張三',3000); INSERT INTO acc VALUES(1002,'張三',1);
1)原子性(Atomicity)
事務是一個完整的操作,事務的各步操作是不可分的(原子的),要么都執行,要么都不執行
模擬銀行轉賬
BEGIN UPDATE acc SET bal=bal-4000 WHERE ID=1001; --轉出4000,但余額只有3000; UPDATE acc SET bal=bal-4000 WHERE ID=1001; --轉入4000 COMMIT; --提交事務 EXCEPTION --1001賬戶轉出時會有異常, WHEN OTHERS THEN --捕獲導常 dbms_output.put_line('賬戶異常,轉賬失敗!'); --提示信息 ROLLBACK; --將數據回滾到轉賬前 END; --查詢發現數據已經回到轉賬前 SELECT * FROM acc;
2)一致性(Consistency):
在事務操作前后,數據必須處於一致狀態
模擬銀行轉賬
DECLARE v_a acc.bal%TYPE; --余額類型 v_b acc.bal%TYPE; v_sal acc.bal%TYPE; --計算總金額 BEGIN SELECT bal INTO v_a FROM acc WHERE ID=1001; --將賬戶A的余額查出 SELECT bal INTO v_b FROM acc WHERE ID=1002; --將賬戶B的余額查出 dbms_output.put_line('轉賬前A的余額: '||v_a); dbms_output.put_line('轉賬前B的余額: '||v_b); dbms_output.put_line('轉賬前A和B的總余額: '||(v_a+v_b)); --開始轉賬 UPDATE acc SET bal=bal-2000 WHERE ID=1001; UPDATE acc SET bal=bal+2000 WHERE ID=1002; COMMIT; --提交 SELECT bal INTO v_a FROM acc WHERE ID=1001; --將賬戶A的余額查出 SELECT bal INTO v_b FROM acc WHERE ID=1002; --將賬戶B的余額查出 dbms_output.put_line('轉賬后A的余額: '||v_a); dbms_output.put_line('轉賬后B的余額: '||v_b); dbms_output.put_line('轉賬后A和B的總余額: '||(v_a+v_b)); EXCEPTION WHEN OTHERS THEN dbms_output.put_line('賬戶異常,轉賬失敗'); --回退到轉賬前 ROLLBACK; -- 失敗時賬戶余額 SELECT bal INTO v_a FROM acc WHERE ID=1001; --將賬戶A的余額查出 SELECT bal INTO v_b FROM acc WHERE ID=1002; --將賬戶B的余額查出 dbms_output.put_line('失敗時A的余額: '||v_a); dbms_output.put_line('失敗時B的余額: '||v_b); dbms_output.put_line('失敗時A和B的總余額: '||(v_a+v_b)); END;
3)隔離性(Isolation):
對數據進行修改的所有並發事務是彼此隔離的,這表明事務必須是獨立的,它不應以任何方式依賴於或影響其他事務
模擬銀行轉賬
--首先轉賬但不提交 DECLARE BEGIN --開始轉賬 UPDATE acc SET bal=bal-2000 WHERE ID=1001; UPDATE acc SET bal=bal+2000 WHERE ID=1002; END; --此時第二個人開始為1001賬戶存款 UPDATE acc SET bal=bal+1000 WHERE ID=1001; --發現一直處於等待狀態, --因為首先轉賬沒有完成,不對同時對一個事務進行處理 --多個用戶同時處理同一事務時,要么得到的是處理前的,要么得到處理后的狀態 --這里返回轉賬並提交 DECLARE BEGIN --開始轉賬 UPDATE acc SET bal=bal-2000 WHERE ID=1001; UPDATE acc SET bal=bal+2000 WHERE ID=1002; COMMIT; END; --再返回第二個人存錢窗口發現已經完成,可以提交 UPDATE acc SET bal=bal+1000 WHERE ID=1001; COMMIT;
讀取事務異常:
1、臟讀:一個事務讀取了另一個事務未提交的數據。
2、不可重復讀:一個事務再次讀取之前曾經讀取過的數據時,發現該數據已經被另一個已提交的事務修改。
3、幻讀:一個事務根據相同的查詢條件,重新執行查詢,返回記錄中包含了與前一次執行查詢返回的記錄不同的行。
事務的隔離級別:
ANSI SQL-92標准中定義的事務級別:
1、Read Uncommitted:最低等級的事務隔離,它僅僅保證了讀取過程中不會取到非法數據。
2、Read Comitted:此級別的事務隔離保證了一個事務不會讀到另一個並行事務已修改但未提交的數據,此級別的事務級別避免了”臟讀“。
3、Repeatable Read:此級別的事務隔離避免了”臟讀“和”不可重復讀“異常現象的出現。一個事務不可能更新已經由另一個事務讀取但未提交(回滾)的數據。
4、Serializable:最高等級的隔離級別,提供了最高等級的隔離機制,三種異常情況都能避免。該事務以串行執行的方式執行。
隔離等級 |
臟讀 |
不可重復讀 |
幻讀 |
Read Uncommitted |
可能 |
可能 |
可能 |
Read Comitted |
不可能 |
可能 |
可能 |
Repeatable Read |
不可能 |
不可能 |
可能 |
Serializable |
不可能 |
不可能 |
不可能 |
Oracle中提供的隔離級別:
1、Read Comitted:Oracle默認的隔離級別,此級別的事務保證了一個事務不會讀到另一個並行事務已修改但未提交的數據,也就是說,此等級的事務避免了"臟讀"。
2、Serializable:最高等級的隔離級別,提供了最高等級的隔離機制,三種異常情況都能避免。
3、Read Only:Read Only是Serializable的子集,指事務中不能有任何修改數據庫中數據的語句(DML),以及修改數據結構的語句(DDL)。只允許讀不允許改。
事務:
在Oracle中不需要專門的語句來開始事務,隱含的事務會在修改數據的第一條語句處開始
結束事務:
- commit語句顯式終止一個事務
- ROLLBACK語句回滾事務
- 執行一條DDL語句,如果DDL語句前面已經有了DML語句,則ORACLE會把前面的DML語句作為一個事務提交
- 用戶斷開與ORACLE連接。用戶當前的事務將被自動提交
- 用戶 進程意外終止,這里用戶當前的事務被回滾
事務控制語句:
1、COMMIT:提交事務,對數據庫的修改進行保存。
2、ROLLBACK:回滾事務,取消對數據庫所做的修改。
3、SAVEPOINT:在事務中創建存儲點。
4、ROLLBACK TO <SAVEPOINT>:將事務回滾到存儲點。
5、SET TRANSACTION:設置事務的屬性
事務控制語句:
SET AUTOCOMMIT=OFF |
取消自動提交 |
SET AUTOCOMMIT=ON |
打開自動提交, |
COMMIT |
提交事務 |
ROLLBACK |
回滾事務,取消對數據庫所做的修改。 |
SAVEPOINT 事務保存點的名稱 |
設置事務保存點 |
ROLLBACK() TO [回滾點] |
回滾操作 |
SET TRANSACTION |
設置事務的屬性 |
COMMIT 和ROLLBACEK可以寫為:COMMIT WORK, ROLLBACK WORK
SAVEPOINT 在事務中創建存儲點
語法: SAVEPOINT[SAVEPOINT_NAME]名字可以不寫
ROLLBACK TO< SAVEPOINT_NAME > 將事務回滾到指定的存儲點
事務控制語句:
SET TRANSACTION:
- SET TRANSACTION語句必須是事務的第一條語句
- 指定事務的隔離級別
- 規定事務回滾事務時使用的存儲空間
設置事務級別:
- SET TRANSACTION READONLY;
- SET TRANSACTION ISOLATION_LEVEL READ COMMITTED;
- SET TRANSACTION ISOLATION_LEVEL SERIALIZABLE;
設置存儲點
--模擬銀行轉賬: SELECT * FROM acc; DECLARE BEGIN UPDATE ACC SET BAL = BAL + 2000 WHERE ID = 1001; --先存入2000但不提交 SAVEPOINT ACC_ADD; --設置存儲點 UPDATE ACC SET BAL = BAL - 6000 WHERE ID = 1001; --轉出6000,余額不足會出現導演 UPDATE ACC SET BAL= BAL + 6000 WHERE ID = 1002; --另一賬戶轉入6000 COMMIT; --提交 EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('數據異常,轉賬失敗!'); ROLLBACK TO ACC_ADD; --回滾到存完2000時設置的存儲點 END;
--銀行轉賬在過程中
SELECT * FROM acc; --建立過程 create or replace procedure proc_tran(fromacc in number,toacc in number,sal in number) is begin dbms_output.put_line('轉賬開始'); UPDATE acc SET bal=bal-sal WHERE id=fromacc; UPDATE acc SET bal=bal+sal WHERE id=toacc; dbms_output.put_line('轉賬成功'); COMMIT; EXCEPTION WHEN OTHERS THEN dbms_output.put_line('賬戶異常,轉賬失敗'); ROLLBACK; end proc_tran; --調用過程 DECLARE BEGIN proc_tran(1001,1002,3000); END;