所謂事務,他是一個操作序列,這些操作要么都執行,要么都不執行,是一個不可分割的工作單元。通俗解釋就是事務是把很多事情當成一件事情來完成,也就是大家都在一條船上,要死一起死,要活一起活。
為什么要引入事務?事務處理可以確保除非事務性單元內的所有操作都成功完成,否則不會永久更新面向數據的資源。通過將一組相關操作組合為一個要么全部成功要么全部失敗的單元,可以簡化錯誤恢復並使應用程序更加可靠。事務結束后,能保證數據庫數據的一致性。例如銀行轉賬,一個賬號扣錢,一個賬號增款,要么都執行,要么都不執行,不能只執行一條,否則會出現賬款錯誤。這樣我們就可以體會到事務的重要性了吧。其實在我們的生活中,很多事情都是要組成事務來執行的。既然它那么重要,下面我們就來深入的了解一下什么是事務吧。
一.事務的四個特征ACID
事務的四個特征非常重要,只有滿足這些特征,才能保證事務執行后只有一個結果:要么成功,要么失敗。
(1)原子性(Atomicity):組成事務處理的語句形成了一個邏輯單元,不能只執行其中的一部分。
(2)一致性(Consistemcy):事務處理前后,數據處於一致狀態,保證數據的無損。
(3)隔離性(Isolation):對數據進行修改的多個事務是彼此隔離的,互不影響。
(4)持久性(Durability):事務完成之后,它對於系統的影響是永久的,該修改即使出現系統故障也將一直保留,真實的修改了數據庫。
示例一
---------創建表 CREATE TABLE bank ( customerName CHAR(10), --顧客姓名 currentMoney number(10) --當前余額 ); ---------添加余額不能小於1的約束 ALTER TABLE bank ADD CONSTRAINT CK_currentMoney CHECK(currentMoney >= 1); ---------插入測試數據 INSERT INTO bank(customerName, currentMoney) VALUES('張三', 1000); INSERT INTO bank(customerName, currentMoney) VALUES('李四', 1); commit; select * from bank; ---------不使用事務完成轉帳操作(總金額異常) update bank set currentMoney=currentMoney-1000 where customerName='張三'; update bank set currentMoney=currentMoney+1000 where customerName='李四'; commit; ---------清空數據, delete bank; select * from bank; ---------使用事務完成轉賬操作不會出現總金額異常 set serveroutput on; declare li_money number(10):=0; begin update bank set currentMoney=currentMoney+1000 where customerName='李四'; select currentMoney into li_money from bank where customerName='李四'; dbms_output.put_line('李四當前的余額是:'||li_money); update bank set currentMoney=currentMoney-1000 where customerName='張三'; exception when others then dbms_output.put_line('撤銷提交'); rollback; end; --轉帳之后查看結果,李四的錢被回滾回去了 select * from bank;
二.回滾到保存點
(1)rollback:回滾到最初狀態,可以參考示例一。
(2)rollback to 保留點:回滾到保留點。
示例二
declare num int; begin savepoint a; --創建保存點a update bank set currentmoney=currentmoney-100 where customername='張三'; savepoint b; --創建保存點b update bank set currentmoney=currentmoney+100 where customername='李四'; savepoint c; --創建保存點c num:=# --從提示框接收一個數據,用於操作回滾到哪一點。 insert into bank values('王五',600); savepoint d; --創建保存點d if num=1 then rollback to a; --當提示框中輸入1時,回滾到保存點a,即全部回滾,相當於rollback; elsif num=2 then rollback to b; --當提示框中輸入2時,回滾到保存點b elsif num=3 then rollback to c; --當提示框中輸入3時,回滾到保存點c else rollback to d; --其他情況下,回滾到保存點d end if; end;
三.事務的隔離級別
從上面的示例中我們可以看到事務帶給我們的巨大好處,保證了數據的一致性,但是,僅僅有保證用事務執行就可以保證數據前后是一致的嗎?在實際情況下,事務是並發執行的,不可避免的會出現多個事務同一時間對相同數據的操作,這樣就會產生各種並發問題。
並發問題:(1)臟讀:事務T1、T2,T1讀取了T2已經更改但還沒有提交的數據,之后,若T2回滾,T1讀到的數據就是臨時無效的臟數據。
(2)不可重復讀:事務T1、T2,T1讀取了一個字段,然后T2更新了該字段,當T1再次讀取該字段時,值就不同了。
(3)幻讀:事務T1、T2,T1讀取了一個字段,T2在在該表中又插入了一些字段,當T1再次讀取時,會多出幾行。
為了解決上面這些問題,引入了隔離級別,顯然,隔離級別是指一個事務與其他事務的隔離程度,隔離級別都有哪些呢,下面簡單介紹了一下。
隔離級別 | 描述 |
read uncommitted(讀取未提交數據) | 允許事務讀取未被其他事務提交的變更,臟讀、不可重復讀和幻讀問題都會出現。 |
read committed(讀取已提交數據) | 只允許事務讀取已被其他事務提交的變更,可以避免臟讀,但不可重復讀和幻讀問題仍然存在。 |
repeatable committed(可重復讀) | 確保一個事務可以多次從一個字段中讀取到相同的值,避免了臟讀、不可重復讀,但幻讀問題仍然存在。 |
serializble(串行化) | 在這個事務執行期間,禁止其他表對該表的插入、刪除、修改操作,所有並發問題都可以避免,但性能低下。 |