.net 跨数据库事务的实现
来源:互联网 发布:中国沿海湿地保护网络 编辑:程序博客网 时间:2024/06/05 05:38
古老的ASP時代,要做Distributed Transaction(分散式交易,指跨越異質資料庫的交易,例如: 將SQL Server跟Oracle的更新動作包成一個Transaction),有個偷懶的方法。在ASP最前端宣告一下<%@ Transaction=Required%>,則整個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無法使用...】的訊息)
- .net 跨数据库事务的实现
- .net 跨数据库事务的实现
- .net 跨数据库事务的实现
- 用Microsoft.net实现数据库事务(一)
- 用Microsoft.net实现数据库事务(二)
- 用Microsoft.net实现数据库事务(三)
- 用Microsoft.net实现数据库事务(四)
- ADO.NET事务的实现
- VB.NET 中启动ADO.NET事务,实现对数据库操作的整体性。
- 实现数据库事务的简单方法ExecuteSqlTran()
- 数据库的事务实现与ACID属性
- 【数据库】事务实现的机制,checkpoint
- 跨数据库事务的解决
- 数据库开发之【ASP.NET页面级别的事务】
- 自己写的实现数据库事务的简单方法ExecuteSqlTran()
- 自己写的实现数据库事务的简单方法ExecuteSqlTran()
- .net中事务的几种实现方式
- 关于.NET编程中各种事务的实现
- sgu259:Printed PR(贪心)
- 使用Mac OS X 终端连接Git@Git.Oschina.Net
- Scrapy中文输出与中文保存
- TIPC 透明通信协议
- 浅析CVE-2013-6282
- .net 跨数据库事务的实现
- Android快速开发之appBase——(3).详解IHolder和IData
- 方块大动员登陆iOS和Android平台,扫码就可立即体验超流畅的俄罗斯方块手游
- 第五届TFC“中国物流与通关事务卓越峰会”在今夏以知识专场的形式拉来帷幕,期待你的参与!
- android Dialog给Activity 传参
- Weblogic 10安装部署以及使用方法
- 在imp数据库时报错1045
- PMC云计算大会再出击 携众厂商高歌猛进
- hihoCoder#1038 : 01背包