交易處理是所有大型資料庫產品的一個關鍵問題,各資料庫廠商都在這個方面花費了很大精力,不同的交易處理方式會導致資料庫效能和功能上的巨大差異。
交易處理也是資料庫管理員與資料庫應用程式開發人員必須深刻理解的一個問題,對這個問題的疏忽可能會導致應用程式邏輯錯誤以及效率低下。
下面我們針對Oracle及SQL Server這兩種當前廣泛使用的大型資料庫產品,探討一下它們在交易處理方面的一些差異。如沒有特殊說明,本文內容適用的資料庫產品版本為Oracle9i及SQL Server 2000,其中的樣本SQL語句,對於Oracle是在SQL*Plus中執行,而對於SQL Server 2000是在osql中執行。
1. 事務的概念
事務可以看作是由對資料庫的若干操作組成的一個單元,這些操作要麼都完成,要麼都取消,從而保證資料滿足一致性的要求。事務的一個典型例子是銀行中的轉帳操作,帳戶A把一定數量的款項轉到帳戶B上,這個操作包括兩個步驟,一個是從帳戶A上把存款減去一定數量,二是在帳戶B上把存款加上相同的數量。這兩個步驟顯然要麼都完成,要麼都取消,否則銀行就會受損失。顯然,這個轉帳操作中的兩個步驟就構成一個事務.
資料庫中的事務還有如下ACID特徵。
ACID分別是四個英文單詞的首寫字母,這四個英文單詞是Atomicity、Consistency、Isolation、Durability,分別翻譯為原子性、一致性、隔離性、持久性。
原子性:指事務中的操作,或者都完成,或者都取消。
一致性:指事務中的操作保證資料庫中的資料不會出現邏輯上不一致的情況,一致性一般會隱含的包括在其他屬性之中。
隔離性:指當前的事務與其他未完成的事務是隔離的。在不同的隔離等級下,事務的讀取操作,可以得到的結果是不同的。
持久性:指對事務發出COMMIT命令後,即使這時發生系統故障,事務的效果也被持久化了。與此相反的是,當在事務執行過程中,系統發生故障,則事務的操作都被復原,即資料庫回到事務開始之前的狀態。
對資料庫中的資料修改都是在記憶體中完成的,這些修改的結果可能已經寫到硬碟也可能沒有寫到硬碟,如果在操作過程中,發生斷電或系統錯誤等故障,資料庫可以保證未結束的事務對資料庫的資料修改結果即使已經寫入磁碟,在下次資料庫啟動後也會被全部撤銷;而對於結束的事務,即使其修改的結果還未寫入磁碟,在資料庫下次啟動後會通過交易記錄中的記錄進行“重做”,即把丟失的資料修改結果重建,並寫入磁碟,從而保證結束事務對資料修改的永久化。這樣也保證了事務中的操作要麼全部完成,要麼全部撤銷。
2. 事務設定及類型的區別
在SQL Server中有三種事務類型,分別是:隱含交易、明確交易、自動認可事務,預設為自動認可。
自動認可,是指對於使用者發出的每條SQL語句,SQL Server都會自動開始一個事務,並且在執行後自動進行提交操作來完成這個事務,也可以說在這種事務模式下,一個SQL語句就是一個事務。
明確交易,是指在自動認可模式下以Begin Transaction開始一個事務,以Commit或Rollback結束一個事務,以Commit結束事務是把事務中的修改永久化,即使這時發生斷電這樣的故障。例如下面是SQL Server中的一個明確交易的例子。Begin Tran
Update emp Set ename=’Smith’ Where empno=7369
Insert Into dept Values(60,’HR’,’GZh’)
Commit
隱含交易,是指在當前會話中用Set Implicit_Transactions On命令設定的事務類型,這時任何DML語句(Delete、Update、Insert)都會開始一個事務,而事務的結束也是用Commit或Rollback。
在Oracle中沒有SQL Server的這些事務類型,預設情況下任何一個DML語句都會開始一個事務,直到使用者發出Commit或Rollback操作,這個事務才會結束,這與SQL Server的隱含交易模式相似。
3. 交易隔離等級
在SQL92標準中,交易隔離等級分為四種,分別為:Read Uncommitted、Read Committed、Read Repeatable、Serializable,其中Read Uncommitted與Read Committed為語句層級的,而Read Repeatable與Serializable是針對事務層級的。
在Oracle和SQL Server中設定交易隔離等級的語句是相同的,都使用SQL92標準文法,即:
Set Transaction Isolation Level Read Committed
上面樣本中的Read Committed可以被替換為其他三種隔離等級中的任意一種。
1) SQL Server中的隔離等級及實現機制
在SQL Server中提供了所有這四種隔離等級。
下面我們討論在SQL Server中,這幾種隔離等級的含義及其實現方式。
Read Uncommitted:一個會話可以讀取其他事務未提交的更新結果,如果這個事務最後以復原結束,這時的讀取結果就可能是錯誤的,所以多數的資料庫應用都不會使用這種隔離等級。
Read Committed:這是SQL Server的預設隔離等級,設定為這種隔離等級的事務只能讀取其他事務已經提交的更新結果,否則,發生等待,但是其他會話可以修改這個事務中被讀取的記錄,而不必等待事務結束,顯然,在這種隔離等級下,一個事務中的兩個相同的讀取操作,其結果可能不同。
Read Repeatable:在一個事務中,如果在兩次相同條件的讀取操作之間沒有添加記錄的操作,也沒有其他更新操作導致在這個查詢條件下記錄數增多,則兩次讀取結果相同。換句話說,就是在一個事務中第一次讀取的記錄保證不會在這個事務期間發生改變。SQL Server是通過在整個事務期間給讀取的記錄加鎖實現這種隔離等級的,這樣,在這個事務結束前,其他會話不能修改事務中讀取的記錄,而只能等待事務結束,但是SQL Server不會阻礙其他會話向表中添加記錄,也不阻礙其他會話修改其他記錄。
Serializable:在一個事務中,讀取操作的結果是在這個事務開始之前其他事務就已經提交的記錄,SQL Server通過在整個事務期間給表加鎖實現這種隔離等級。在這種隔離等級下,對這個表的所有DML操作都是不允許的,即要等待事務結束,這樣就保證了在一個事務中的兩次讀取操作的結果肯定是相同的。
2) Oracle中的隔離等級及實現機制
在Oracle中,沒有Read Uncommitted及Repeatable Read隔離等級,這樣在Oracle中不允許一個會話讀取其他事務未提交的資料修改結果,從而避免了由於交易回復發生的讀取錯誤。Oracle中的Read Committed和Serializable層級,其含義與SQL Server類似,但是實現方式卻大不一樣。
在Oracle中,存在所謂的復原段(Oracle9i之前版本)或撤銷段(Oracle9i版本),Oracle在修改資料記錄時,會把這些記錄被修改之前的結果存入復原段或撤銷段中,就是因為這種機制,Oracle對於交易隔離等級的實現與SQL Server截然不同。在Oracle中,讀取操作不會阻礙更新操作,更新操作也不會阻礙讀取操作,這樣在Oracle中的各種隔離等級下,讀取操作都不會等待更新事務結束,更新操作也不會因為另一個事務中的讀取操作而發生等待,這也是Oracle交易處理的一個優勢所在。
Oracle預設的設定是Read Committed隔離等級(也稱為語句層級的隔離),在這種隔離等級下,如果一個事務正在對某個表進行DML操作,而這時另外一個會話對這個表的記錄進行讀取操作,則Oracle會去讀取復原段或撤銷段中存放的更新之前的記錄,而不會象SQL Server一樣等待更新事務的結束。
在Serializable隔離等級(也稱為事務層級的隔離),事務中的讀取操作只能讀取這個事務開始之前已經提交的資料結果。如果在讀取時,其他事務正在對記錄進行修改,則Oracle就會在復原段或撤銷段中去尋找對應的原來未經更改的記錄(而且是在讀取操作所在的事務開始之前存放於復原段或撤銷段的記錄),這時讀取操作也不會因為相應記錄被更新而等待。
4. DDL語句對事務的影響
1) Oracle中DDL語句對事務的影響
在Oracle中,執行DDL語句(如Create Table、Create View等)時,會在執行之前自動發出一個Commit命令,並在隨後發出一個Commit或者Rollback命令,也就是說,DDL會象如下偽碼一樣執行:Commit;
DDL_Statement;
If (Error) then
Rollback;
Else
Commit;
End if;
我們通過分析下面例子來看Oracle中,DDL語句對事務的影響:Insert into some_table values(‘Before’);
Creaate table T(x int);
Insert into some_table values(‘After’);
Rollback;
由於在Oracle執行Create table語句之前進行了提交,而在Create table執行後也會自動發出Commit命令,所以只有插入After的行被復原,而插入Before的行不會被復原,Create table命令的結果也不會被復原,即使Create table語句失敗,所進行的Before插入也會被提交。如果最後發出Commit命令,因為插入Before及Create table的操作結果已經在之前提交,所以Commit命令影響的只有插入After的操作。
2) SQL Server中DDL語句對事務的影響
在SQL Server中,DDL語句對事務的影響與其他DML語句相同,也就是說,在DML語句發出之前或之後,都不會自動發出Commit命令。
在SQL Server 2000中,對於與上面Oracle同樣的例子,最後發出Rollback後,資料庫會復原到插入Before之前的狀態,即插入Before和After的行都會被復原,資料表T也不會被建立。
如果最後發出Commit操作,則會把三個操作的結果全部提交。
5. 使用者斷開資料庫連接對事務的影響
另外,對應於Oracle的管理用戶端工具SQL*Plus,在SQL Server 2000中是osql,兩種管理工具都是命令列工具,使用方式及作用也類似,但是在SQL*Plus中,使用者退出串連時,會自動先發出Commit命令,然後再退出,而在osql中,如果使用者退出串連,會自動發出Rollback命令,這對於SQL Server的自動認可模式沒有什麼影響,但如果處於隱含交易模式,其影響是顯而易見的。對於兩種資料庫產品的其他用戶端管理工具也有類似的不同之處。