本節主要介紹Sql語句,SqlTransaction和TransactionScope這三種使用事務的方法。
本節的所有例子都在sql server 2008和vs 2008環境下運行通過,如果沒有sql server2008,那麼使用sql server 2005也一樣,但是sql se rver 2000上是無法運行通過的,因為某些sql語句在2000中不支援。請大家注意這點。
請先執行下面的指令碼,在原生資料庫執行個體中建立測試資料庫,以方便運行例子。
--建庫<br />IF EXISTS (SELECT name FROM sys.databases WHERE name = N'TransTestDb')<br />drop database [TransTestDb]</p><p>CREATE DATABASE [TransTestDb];</p><p>--建表<br />use [TransTestDb]<br />go<br />IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TransTestTable]') AND type in (N'U'))<br />drop table [TransTestTable]</p><p>CREATE TABLE [dbo].[TransTestTable](Id int, [Name] varchar(16));</p><p>--初始值<br />use [TransTestDb]<br />go<br />insert into [TransTestTable]<br />select 1,'a' union<br />select 2,'b' union<br />select 3,'c';
首先介紹利用Sql語句來使用事務。Sql Server2005/2008提供了begin tran,commit tran和rollback tran三個語句來顯示的使用事務。begin tran表示事務開始,commit tran表示事務提交,rollback tran表示交易回復。具體代碼如下:
begin try<br />begin tran<br />insert into dbo.TransTestTable values (66,'66');<br />update dbo.TransTestTable set [Name] = '77' where [Id] = 66;<br />--RAISERROR ('Error raised in TRY block.',16,1);<br />commit tran<br />end try<br />begin catch<br />rollback tran<br />end catch
代碼中的begin try和begin catch是捕獲異常時使用的,只在sql server2005/2008中支援,sql server 2000上不支援這個語句。在begin try 和 end try之間的代碼運行時如果發生異常,則程式會跳轉到begin catch和end catch中執行相關的rollback tran復原操作。在begin tran和commit tran之間就是一個事務,insert和update必須同時成功,否則就同時失敗。RAISERROR 陳述式的意思是拋出一個異常,只在sql server2005/2008中支援,sql server 2000上不支援這個語句。
執行上面的代碼,我們會發現,插入和更新同時都成功了。把RAISERROR的注釋去掉後,再執行,我們會發現,插入和更新都復原了。因為RAISERROR拋出異常後,沒有執行到commit tran,而是直接執行begin catch裡面的rollback tran復原語句了。
下面介紹SqlTransaction的使用方法。SqlTransaction是System.Data.SqlClient命名空間下的一個事務類,主要方法有Commit()和Rollback()兩個函數,更多方法和屬性請參考MSDN。具體代碼如下:
static void Main(string[] args)<br /> {</p><p> SqlConnection sqlConn = new SqlConnection(<br /> ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString);<br /> SqlTransaction sqlTrans = null;<br /> try<br /> {<br /> sqlConn.Open();<br /> sqlTrans = sqlConn.BeginTransaction();//事務開始<br /> SqlCommand sqlComm = new SqlCommand("", sqlConn, sqlTrans);<br /> sqlComm.CommandTimeout = 120;<br /> sqlComm.CommandType = System.Data.CommandType.Text;</p><p> string insertSql = "insert into dbo.TransTestTable values (66,'66');";<br /> string updateSql = "update dbo.TransTestTable set [Name] = '77' where [Id] = 66;";</p><p> sqlComm.CommandText = insertSql;<br /> sqlComm.ExecuteNonQuery();//執行insert</p><p> sqlComm.CommandText = updateSql;<br /> sqlComm.ExecuteNonQuery();//執行update<br /> //throw new Exception("test exception.the transaction must rollback");</p><p> sqlTrans.Commit();//事務提交<br /> }<br /> catch (Exception ex)<br /> {<br /> sqlTrans.Rollback();//交易回復<br /> Console.WriteLine(ex.Message);<br /> }<br /> finally<br /> {<br /> if (sqlConn.State != System.Data.ConnectionState.Closed)<br /> sqlConn.Close();<br /> }</p><p> Console.ReadLine();<br /> }
上面的代碼顯示了SqlTransaction類的基本使用方法。首先使用SqlConnection建立串連後,sqlConn.BeginTransaction()表示事務的開始,在執行一些基本操作後(代碼是執行一個insert和一個update)後,執行sqlTrans.Commit();表示事務提交,這時候,剛才insert和update的資料在資料庫才能被使用。如果把throw new Exception("test exception.the transaction must rollback");這句的注釋去掉,我們會發現,程式沒有執行提交,而是直接執行了catch中的Rollback(),進行了復原。那麼剛才的insert和update一起被復原。
最後看一下TransactionScope的基本用法。TransactionScope繼承IDisposable介面,所以一般在using中使用。具體代碼如下:
static void Main(string[] args)<br />{<br /> using (TransactionScope scope = new TransactionScope())<br /> {<br /> SqlConnection sqlConn = new SqlConnection(<br /> ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString);<br /> sqlConn.Open();</p><p> string insertSql = "insert into [TransTestTable] values(11,'11')";<br /> string updateSql = "update [TransTestTable] set [Name] = '111' where [Id] = 11";</p><p> SqlCommand sqlComm = new SqlCommand(insertSql, sqlConn);<br /> sqlComm.CommandType = System.Data.CommandType.Text;<br /> sqlComm.ExecuteNonQuery();</p><p> sqlComm = new SqlCommand(updateSql, sqlConn);<br /> sqlComm.CommandType = System.Data.CommandType.Text;<br /> sqlComm.ExecuteNonQuery();</p><p> sqlConn.Close();</p><p> scope.Complete();<br /> }</p><p> Console.ReadLine();<br />}
在using中定義了一個TransactionScope,相當於定義了一個事務範圍即這個事務範圍為using內。程式執行了兩個動作,一個insert,一個update,最後執行了scope.Complete();相當於提交事務。如果把scope.Complete();注釋掉,我們會發現insert和update都被復原了,因為在using範圍內,如果沒有提交命令,那麼scope在銷毀時,會自動復原所有的操作
以上就是三種事務的基本使用方法,在此基礎之上,還可以引申出更多的問題,比如嵌套事務,三種方法的混合使用等問題。在此就不一一列舉了。