剖析概括ADO.NET執(zhí)行事務(wù)
事務(wù)往往是我們很難處理的一部分,這里結(jié)合我的經(jīng)驗(yàn)和大家來談?wù)勱P(guān)于ADO.NET執(zhí)行事務(wù)。如果要將多項(xiàng)任務(wù)綁定在一起,使其作為單個(gè)工作單元來執(zhí)行,可以使用ADO.NET中的事務(wù)。例如,假設(shè)應(yīng)用程序執(zhí)行兩項(xiàng)任務(wù)。首先使用訂單信息更新表。然后更新包含庫存信息的表,將已訂購的商品記入借方。如果任何一項(xiàng)任務(wù)失敗,兩個(gè)更新均將回滾。
確定事務(wù)類型
事務(wù)如果是單階段事務(wù),并且由數(shù)據(jù)庫直接處理,則屬于本地事務(wù)。事務(wù)如果由事務(wù)監(jiān)視程序進(jìn)行協(xié)調(diào)并使用故障保護(hù)機(jī)制(例如兩階段提交)解決事務(wù),則屬于分布式事務(wù)。每個(gè).NETFramework數(shù)據(jù)提供程序使用自己的Transaction對(duì)象來執(zhí)行本地事務(wù)。如果要求在SQLServer數(shù)據(jù)庫中執(zhí)行,請(qǐng)選擇System.Data.SqlClient事務(wù)。對(duì)于Oracle事務(wù),使用System.Data.OracleClient提供程序。此外,還提供了一個(gè)新的DbTransaction類,用于編寫需要事務(wù)并且與提供程序無關(guān)的代碼。
在服務(wù)器上執(zhí)行時(shí),事務(wù)最有效。如果使用的SQLServer數(shù)據(jù)庫廣泛使用顯式事務(wù),應(yīng)考慮使用Transact-SQLBEGINTRANSACTION語句以存儲(chǔ)過程的形式編寫這些事務(wù)。有關(guān)執(zhí)行服務(wù)器端事務(wù)的更多信息,請(qǐng)參見“SQLServer聯(lián)機(jī)圖書”。
使用單個(gè)連接ADO.NET執(zhí)行事務(wù)
在ADO.NET中,使用Connection對(duì)象控制事務(wù)??梢允褂肂eginTransaction方法啟動(dòng)本地事務(wù)。開始事務(wù)后,可以使用Command對(duì)象的Transaction屬性在該事務(wù)中登記一個(gè)命令。然后,可以根據(jù)事務(wù)組件的成功或失敗,提交或回滾在數(shù)據(jù)源上進(jìn)行的修改。不應(yīng)對(duì)本地事務(wù)使用EnlistDistributedTransaction方法。
#T#事務(wù)的作用域限于該連接。以下示例執(zhí)行顯式事務(wù),該事務(wù)由try塊中兩個(gè)獨(dú)立的命令組成。這兩個(gè)命令對(duì)AdventureWorksSQLServer2005示例數(shù)據(jù)庫的Production.ScrapReason表執(zhí)行INSERT語句,如果沒有引發(fā)異常,則提交。如果引發(fā)異常,catch塊中的代碼將回滾事務(wù)。如果在事務(wù)完成之前事務(wù)中止或連接關(guān)閉,事務(wù)將自動(dòng)回滾。
按照下列步驟ADO.NET執(zhí)行事務(wù)。
1.調(diào)用SqlConnection對(duì)象的BeginTransaction方法,以標(biāo)記事務(wù)的開始。BeginTransaction方法返回對(duì)事務(wù)的引用。此引用分配給在事務(wù)中登記的SqlCommand對(duì)象。
2.將Transaction對(duì)象分配給要執(zhí)行的SqlCommand的Transaction屬性。如果在具有活動(dòng)事務(wù)的連接上執(zhí)行命令,并且尚未將Transaction對(duì)象配給Command對(duì)象的Transaction屬性,則會(huì)引發(fā)異常。
3.執(zhí)行所需的命令。
4.調(diào)用SqlTransaction對(duì)象的Commit方法完成事務(wù),或調(diào)用Rollback方法結(jié)束事務(wù)。如果在Commit或Rollback方法執(zhí)行之前連接關(guān)閉或斷開,事務(wù)將回滾。
以下代碼示例演示對(duì)MicrosoftSQLServer使用ADO.NET的事務(wù)邏輯。
- UsingconnectionAsNewSqlConnection(connectionString)
- connection.Open()
- 'Startalocaltransaction.
- DimsqlTranAsSqlTransaction=connection.BeginTransaction()
- 'Enlistacommandinthecurrenttransaction.
- DimcommandAsSqlCommand=connection.CreateCommand()
- command.Transaction=sqlTran
- Try
- 'Executetwoseparatecommands.
- command.CommandText=_
- "INSERTINTOProduction.ScrapReason(Name)VALUES('Wrongsize')"
- command.ExecuteNonQuery()
- command.CommandText=_
- "INSERTINTOProduction.ScrapReason(Name)VALUES('Wrongcolor')"
- command.ExecuteNonQuery()
- 'Committhetransaction
- sqlTran.Commit()
- Console.WriteLine("Bothrecordswerewrittentodatabase.")
- CatchexAsException
- 'Handletheexceptionifthetransactionfailstocommit.
- Console.WriteLine(ex.Message)
- Try
- 'Attempttorollbackthetransaction.
- sqlTran.Rollback()
- CatchexRollbackAsException
- 'ThrowsanInvalidOperationExceptioniftheconnection
- 'isclosedorthetransactionhasalreadybeenrolled
- 'backontheserver.
- Console.WriteLine(exRollback.Message)
- EndTry
- EndTry
- EndUsing