跨数据库事务的实现(.net4.0)

简介: http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece7631046893b4c4380143fd3d1027fa3c215cc7905041724b4fd70620d548d98297a40e91a1ab1a12b733d04...
http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece7631046893b4c4380143fd3d1027fa3c215cc7905041724b4fd70620d548d98297a40e91a1ab1a12b733d0422bd9bcb8b4adfb891232f8c2134721b834112d304bb8e1b65972f875a9ef34ea1adf043d2ed8c928814179d13127bf0f089580a03ca1ee76445f4d19c5f142f07cb9e2711894e075e885536a14689f7421a10f6f6ca5d3cd45ba3766097b844c72966b6&p=8b2a954eca934eaf5fb0c660465cc6&newp=9b49df16d9c34afb19f5c4710d1197231615d70e3cd4d6152b958b&user=baidu&fm=sc&query=%2Enet+sqlserver2008+%BF%E7%CA%FD%BE%DD%BF%E2%CA%C2%CE%F1&qid=&p1=10

古老的ASP時代,要做Distributed Transaction(分散式交易,指跨越異質資料庫的交易,例如: 將SQL Server跟Oracle的更新動作包成一個Transaction),有個偷懶的方法。在ASP最前端宣告一下,則整個ASP中的所有資料庫操作,不管Oracle、SQL、Sybase,通通會自動包成Transaction,不用多寫半行Code。

不過,這種寧 可錯殺一百,不可錯放一個的做法效能有點鳥(連沒必要的SELECT動作也被包入Transaction)。會寫VB COM的人多半會寫顆Support Transaction的COM+元件,用來執行特定的資料庫的更新。而多顆異質資料庫的Transactional元件可以再包出一個大 Transaction。不過,這得另外寫COM,註冊到COM+ Application中,多了些額外手續。

ASP.NET 1.x誕生後,針對分散式交易,提供了一個四不像的做法:
寫一顆繼承自System.EnterpriseService.ServicedComponent的元件,內含更新資料庫的程式邏輯,再設定 TransactionAttribute,然後要Strong-Named/Signed,包上COM+的皮,註冊放入COM+ Application中。

呃... 好像比以前寫COM+還麻煩,堂堂的.NET還是得回頭靠COM+才能實踐分散式交易,會不會有點...

終於.NET 2.0中,針對分散式交易做出了改良。System.Transactions.TransactionScope讓大家有機會重回ASP時代的美妙時光,可以將任意一段資料庫操作包成一個Transaction,不需要額外的手工。例如以下的範例: (要Oracle支援Transaction,記得安裝Oracle Service For Microsoft Transaction Server,不然會百忙一場。)



    21 TransactionOptions options = new TransactionOptions();

    22 options.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;

    23 options.Timeout = new TimeSpan(0, 2, 0);

    24 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options))

    25 {

    26     try

    27      {

    28          using (SqlConnection sqlCn = new SqlConnection("Data Source=(local); User Id=scott; Password=tigger; Initial Catalog=Lab"))

    29           {

    30               SqlCommand cmd = new SqlCommand("INSERT INTO tblAccount (Account, Password, Username) VALUES (@acct, @pwd, @name)", sqlCn);

    31                cmd.Parameters.Add("@acct", SqlDbType.NVarChar).Value = "EMP" + DateTime.Now.ToString("HHmmss");

    32                cmd.Parameters.Add("@pwd", SqlDbType.NVarChar).Value = "PWD";

    33                cmd.Parameters.Add("@name", SqlDbType.NVarChar).Value = "NAME" + DateTime.Now.ToString("HHmmss");

    34                sqlCn.Open();

    35                cmd.ExecuteNonQuery();

    36           }

    37          //** 實測結果,ODP.NET 9207不Support TransactionScope,必須用.NET 2.0的System.Data.OracleClient

    38          using (OracleConnection oraCn = new OracleConnection("Data Source=MYORA; User Id=scott; Password=tigger;"))

    39           {

    40               OracleCommand cmd = new OracleCommand("INSERT INTO MYTABLE.tblAccount (Account, Password, Username) VALUES (:acct, :pwd, :name)", oraCn);

    41                cmd.Parameters.Add(":acct", OracleType.VarChar).Value = "EMP" + DateTime.Now.ToString("HHmmss")

    42                cmd.Parameters.Add(":pwd", OracleType.VarChar).Value = "PWD";

    43                cmd.Parameters.Add(":name", OracleType.VarChar).Value = "NAME" + DateTime.Now.ToString("HHmmss");

    44                oraCn.Open();

    45                cmd.ExecuteNonQuery();

    46           }

    47          //在scope.Complete();後才算Commit!

    48           scope.Complete();

    49      }

    50     catch (Exception ex)

    51      {

    52          //只要沒有scope.Complete(),先前的動作都會Rollback

    53           Response.Write(ex.Message);

    54      }

    55 }



很簡短吧? (有寫過ServicedComponent的人才能感受出它的好呀!!) 為了證實Transaction效果,我在48行設Breakpoint,則中斷未scope.Complete前,SQL的tblAccount會被鎖 定無法SELECT,而ORACLE中則SELECT不到新增的資料(可見SQL用的是Lock大法,ORACLE專攻 Snapshot);scope.Complete後,二者的新資料就都出現了。

同時,我還試 了故意ORACLE新增動作失敗或不做scope.Complete(),則SQL的tblAccount的新增資料就不會出現。由此,可以驗證以上的程 式的確實踐了分散式交易!! 而TransactionScope的確比.NET 1.x的ServicedComponent方便多了,大幅減少異質資料庫包成交易的複雜度。

我曾試著用ODP.NET 9207取代System.Data.OracleClient,測試結果顯示ODP.NET 9207無法參與TrasactionScope物件所建立的交易。後來找到Oracle的ODP.NET FAQ,提到了從ODP.NET 10.2.0.2.20起才支援.NET 2.0的System.Transactions,想用ODP.NET的人要留意。

最後還有一點要注意,如果你的SQL在遠端主機上,用的又是Windows 2003平台,則還有好幾個關節要打通。包含了MSDTC在Windows 2003 SP1上有些選項要調整。還有,你可能會連線失敗,並得到以下這類訊息:
Communication with the underlying transaction manager has failed.
The transaction has already been implicitly or explicitly committed or aborted.

經驗中多半是防火牆的傑作,我的私房解法是在Windows Firewall上開放MSDTC.EXE程式的所有對外連線,問題就可解決。微軟有篇專題文章,介紹MSDTC與Firewall間的愛恨情仇,有興趣的人也可以去挖挖寶。


【一】加入System.Transactions參考
於專案中加入參考,選擇[.NET]頁籤,往下拖拉便可以看到System.Transactions如下圖:


【二】開啟MSDTC的服務
從[控制台]→[系統管理工具]→ 開啟[服務],可以看到有個【Distributed Transaction Coordinator】服務把它啟動
(PS:如果不啟動,程式執行時會發生【伺服器...上的MSDTC無法使用...】的訊息)

目录
相关文章
|
3月前
|
SQL 关系型数据库 MySQL
乐观锁在分布式数据库中如何与事务隔离级别结合使用
乐观锁在分布式数据库中如何与事务隔离级别结合使用
|
22天前
|
SQL 关系型数据库 MySQL
乐观锁在分布式数据库中如何与事务隔离级别结合使用
乐观锁在分布式数据库中如何与事务隔离级别结合使用
|
29天前
|
SQL 开发框架 .NET
ASP.NET连接SQL数据库:详细步骤与最佳实践指南ali01n.xinmi1009fan.com
随着Web开发技术的不断进步,ASP.NET已成为一种非常流行的Web应用程序开发框架。在ASP.NET项目中,我们经常需要与数据库进行交互,特别是SQL数据库。本文将详细介绍如何在ASP.NET项目中连接SQL数据库,并提供最佳实践指南以确保开发过程的稳定性和效率。一、准备工作在开始之前,请确保您
137 3
|
15天前
|
数据库
什么是数据库的事务隔离级别,有什么作用
【10月更文挑战第21】什么是数据库的事务隔离级别,有什么作用
12 3
|
15天前
|
存储 关系型数据库 数据挖掘
什么是数据库的事务隔离级别
【10月更文挑战第21】什么是数据库的事务隔离级别
11 1
|
21天前
|
存储 数据库 数据库管理
数据库事务安全性控制如何实现呢
【10月更文挑战第15天】数据库事务安全性控制如何实现呢
|
21天前
|
存储 数据库 数据库管理
什么是数据库事务安全性控制
【10月更文挑战第15天】什么是数据库事务安全性控制
|
21天前
|
供应链 数据库
数据库事务安全性控制有什么应用场景吗
【10月更文挑战第15天】数据库事务安全性控制有什么应用场景吗
|
21天前
|
存储 关系型数据库 MySQL
数据库的事务控制
【10月更文挑战第15天】数据库的事务控制
20 2
|
21天前
|
SQL 关系型数据库 数据库
如何在数据库中实现事务控制呢
【10月更文挑战第15天】如何在数据库中实现事务控制呢
11 1
下一篇
无影云桌面