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