關于Oracle的事務
?
?
事務的ACID特性
?
??? 1、原子性(Atomicity)
?
??? 事務的原子性是指事務中包含的所有操作要么都做,要么都不做,保證數據庫是一致的。
?
??? 例如:A帳戶向B帳戶劃賬1000,則先將A減少1000,再將B增加1000,這兩個動作要么都提交,要么都回退,不可能發生一個有效、一個無效的情況。
?
??? 2、一致性(Consistency)
?
??? 一致性是指數據庫在事務操作前和事務處理后,其中的數據必須都滿足業務規則約束。
?
??? 例如:A、B帳戶的總金額在轉賬前和轉帳后必須一致,其中的不一致必須是短暫的,在事務提交前才會出現的。
??? 再如:約定B帳戶不能多于1000元,則A轉出1000成功,B轉入1000失敗,最終由原子性得到——整個事務回滾
?
??? 3、隔離性(Isolation)
?
??? 隔離性是數據庫允許多個并發事務同時對齊數據進行讀寫和修改的能力,隔離性可以防止多個事務并發執行時由于交叉執行而導致數據的不一致。
?
??? 例如:在A、B之間轉帳時,C同時向A轉帳,若同時進行則A、B之間的一致性不能得到滿足。所以在A、B事務執行過程中,其他事務不能訪問(修改)當前相關的數值。
?
??? 4、持久性(Durability)
?
??? 持久性表示為:事務處理結束后,對數據的修改就是永久的,即便系統故障也不會丟失。
?
??? 在提交之前如果系統故障,則所有信息全部丟失。提交之后數據存放在磁盤中,是永久性的。
?
?
?
事務的控制
?
??? 事務的開始是隱形聲明的,不用也沒有語句可以進行操作,默認從對數據的修改開始就開始了當前事務。
?
??? 對數據庫的設置主要有一下語句:
??? SET TRANSACTION-----設置事務屬性
??? SET CONSTRANS-------設置約束模式
??? SAVEPOINT-----------建立存儲點
??? RELEASE SAVEPOINT---釋放存儲點
??? ROLLBACK------------回滾
??? COMMIT--------------提交
?
1、設置事務屬性
?
??? 設置事務屬性主要可以用來完成以下工作:
????? * 指定事務的隔離層
????? * 規定回滾事務時所使用的存儲空間
????? * 命名事務
?
????? 注:SET TRANSACTION必須是事務的第一個語句。并在事務終止后自動失效。
?
??? SET TRANSACTION ISOLATION LEVEL READ COMMITED
?
????? A事務設置為READ COMMITED,該開始后B事務修改了數據,此時A無法得到新數據,B提交之后,A可以查詢到更新數據。
A不可能錯讀,但可能發生假讀和非重復讀。
????? 在需要并發數很大時應該使用READ COMMITED,對于多用戶并發的性能和響應速度都比較好。
?
??? SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
?
????? 事務和事務之間完全隔離開,事務以串行的方式執行。不是說必須等一個結束,而是事務一旦開始,在結束之前查詢到的數據永遠是開始時刻的數據。由于留存的模式會比較多,所以會消耗一定的系統資源。
?
??? SET TRANSACTION READ ONLY
?
????? 當前事務不能有任何修改數據的操作,READ ONLY是SERIALIZABLE的一個子集,基本上屬于最高的安全級。
?
??? SET TRANSACTION READ WRITE
?
????? 在READ的基礎上增加WRITE權限,不常用
?
?
2、設置約束延期性
?
??? 在操作過程中可能需要違反約束向表中插入重復的數據,其實需要設置約束延期性。
?
??? 設置格式如下:
??? SET CONSTRAINT ALL | <constraint_name>
??? DEFERRED | IMMEDIATE
?
??? 可以選擇要延期的約束名,也可以使用ALL關鍵字延期所有的約束
??? DEFERRED表示延期,IMMEDIATE表示應用
?
??? 注:理論上在COMMIT前需要設置回IMMEDIATE,但是系統可以隱式自動完成這一操作。
?
?
??? 注意:要使用延遲的約束,必須在創建時就進行說明:
?
??? ALTER TABLE T1 ADD CONSTRAINT <constraint_name> DEFERRABLE INITIALLY IMMEDIATE
?
??? 后面的DEFERRABLE 指名可以使用延遲,INITIALLY 設定了初始值
?
?
3、存儲點
?
??? 由于事務太大,一次回滾會對系統造成很大的壓力。而且有時候在某一段特定的代碼附近會特別發生錯誤而回滾。這時就需要在希望的地方設置一個存儲點,可以顯示得操作數據在發生錯誤時回滾到指定的存儲點,而節省不必要的開銷。
?
??? 創建格式如下:
??? SAVEPOINT <savepoint_name>
?
??? 使用格式如下:
??? ROLLBACK TO [SAVEPOINT] <savepoint_name>
?
?
4、結束事務
?
??? 以下操作為將事務結束:
?
??? * 使用COMMIT提交事務,數據被永久保存
??? * 使用ROLLBACK回滾事務(不包括回滾到存儲點)
??? * 執行DDL時,結束默認COMMIT
??? * 用戶斷開連接,此時事務自動COMMIT
??? * 進程意外中止,此時事務自動ROLLBACK
?
??? 注:事務COMMIT時會生成一個唯一的系統變化號(SCN)保存到事務表
?
?
?
?
?
?
附:關于事務相關的數據字典
=========================================================================================================
晶晶實驗七之事務表篇
?
??? 回滾段頭中,有一項非常重要的信息,就是事務表。對事務表頻繁的訪問,可能會造成回滾段頭的爭用.了解什么樣的操作會訪問事務表,對于了解回滾段頭爭用的原因非常重要.下面我們來做一些實驗來驗證一下,什么樣的操作才會訪問事務表.
??? 首先簡單介紹一個視圖,備份x$bh.對這個視圖我想大家都有一定的了解,bh即buffer header 的簡寫.在buffer? header中有一個TCH 列,表示塊被訪問的次數.我們通過他來驗證事務表什么時候被訪問.需要注意的是.TCH列每3秒,才會重新計算一次,3秒之內無論訪問某一個塊多少次.TCH列只會增加1.
? 在會話A開啟一個事務后:
步驟一:通過v$transaction視圖找到XID
SQL> select xidusn,ubablk,ubafil from v$transaction;
??? XIDUSN???? UBABLK???? UBAFIL
---------- ---------- ----------
??????? 13???????? 97????????? 5
步驟二:通過回滾段編號,可得知事務所占回滾段名,并用此查找事務頭塊號,文件號
SQL> select header_block,header_file from dba_segments where segment_name='_SYSSMU13$';
HEADER_BLOCK HEADER_FILE
------------ -----------
????????? 41?????????? 5
步驟三:查看x$bh視圖中,TCH值的增加.
SQL> select addr,tch from x$bh where dbarfil=5 and dbablk=41;
ADDR??????????? TCH
-------- ----------
080B5208???????? 41
步驟四:查找完TCH后,馬上執行要測試的命令(會話B),
SQL> select * from jj_3;
??????? ID NA
---------- --
???????? 1 aa
???????? 2 aa
???????? 3 aa
???????? 4 aa
???????? 5 CN
步驟五:再次查看x$bh視圖
SQL> select addr,tch from x$bh where dbarfil=5 and dbablk=41;
ADDR??????????? TCH
-------- ----------
080B5208???????? 42
注意:步驟三四五應盡快完成.避免oracle的其他內部操作影響測試結果.(因為oracle內部的操作也會造成回滾段頭的tch值增加,特別在10G中,這種情況更為明顯,不過我沒有跟蹤是什么oracle的內部操作造成的)
??? 小結:從結果集來看,在另一會話中訪問未提交數據的select語句會訪問事務表,那么其他的DML操作呢?(希望大家也都試試,我的結果是都會增加TCH值).上面我的步驟四是全表掃描.
??? 如果我的表有兩個塊,分別是塊一塊二,在塊一中修改行A,按照rowid訪問塊一中的行B,這樣會訪問事務表嗎?如果
按照rowid訪問塊二中的行,會訪問事務表嗎?下面我來實驗下看結果是什么:
步一:利用函數查看該表的塊號.
SQL> select rowid,dbms_rowid.rowid_block_number(rowid) from jj_3;
ROWID????????????? DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
------------------ ------------------------------------
AAAMvjAAKAAAAEdAAA????????????????????????????????? 285
AAAMvjAAKAAAAEdAAB????????????????????????????????? 285
AAAMvjAAKAAAAEdAAC????????????????????????????????? 285
AAAMvjAAKAAAAEeAAA????????????????????????????????? 286
步二: 在B會話中通過AAAMvjAAKAAAAEdAAC修改表.
SQL> update jj_3 set id=10 where rowid='AAAMvjAAKAAAAEdAAC';
已更新 1 行。
步三: 在A會話中通過AAAMvjAAKAAAAEdAAA查看行
SQL> select * from jj_3 where rowid='AAAMvjAAKAAAAEdAAA';
??????? ID NA
---------- --
???????? 4 aa
在做步一和二之前,先查看一下X$BH,因為他會因為oracle的內部操作而增加,
實驗前查看結果:
SQL> select addr,tch from x$bh where dbarfil=5 and dbablk=41;
ADDR??????????? TCH
-------- ----------
080B51BC???????? 63
實驗后查看結果:
SQL> select addr,tch from x$bh where dbarfil=5 and dbablk=41;
ADDR??????????? TCH
-------- ----------
080B51BC???????? 64
? 結論一:在塊一中修改行A,按照rowid訪問塊一中的行B,這樣會訪問事務表;再試試不同的塊
操作前先查看下X$BH:
SQL> select addr,tch from x$bh where dbarfil=5 and dbablk=41;
ADDR??????????? TCH
-------- ----------
080B51BC???????? 67
接著剛才的實驗,我又訪問了不同的塊:
SQL> select * from jj_3 where rowid='AAAMvjAAKAAAAEeAAA';
??????? ID NA
---------- --
???????? 4 aa
再次查看X$BH的結果是:
SQL> select addr,tch from x$bh where dbarfil=5 and dbablk=41;
ADDR??????????? TCH
-------- ----------
080B51BC???????? 67
結果很明顯了,用rowid訪問不同的塊,是不會增加TCH值的.也就是說不會有CR塊產生.
在晶晶實驗六中,已經證明了在生成CR塊時,oracle可以根據數據塊頭部的ITL槽中的UBA,找到存放數據塊回滾信息的回
滾塊和回滾記錄,通過這個UBA就可以構造CR塊咯,oracle為什么還要再去訪問事務表呢?這是因為,oracle的提交有時會
是延遲提交.oracle并不清除延遲提交所涉及的塊中的事務信息,如:事務所占ITL槽和行鎖.而把清除事務信息這個操作
放到了以后的塊清除中(塊清除在以后的實驗會詳細講述),oracle這樣做的目的是為加快提交速度.如果一個事務涉及
到了過多的塊,單單是提交時清除每個塊中的事務信息就需要耗費很長時間.這降低了提交速度.有可能使提交成為最易
引起爭用的操作.當事務提交時,對事務所涉及的塊,不做任何操作,塊將保持事務仍在持續時的信息.當一個select操作
查詢到這個塊時,ITL槽中的提交標志為未提交,但實際上這個事務是已經提交的.就是因為有了延遲提交oracle無法根
據ITL槽中的提交標志來判斷一個塊中的事務是否真的提交.他必須根據ITL中的XID 去訪問事務表.才能確定此塊中的
事務是否真的提交.在生成CR塊前,oracle先要判斷是否真的有必要為此塊生成CR塊.這就要去訪問事務表.
?
?