在.net 2.0 中执行分布式事务:隐式事务篇(SQL Server 与 Oracle)

项目涉及到多个数据库的查询更新操作,也就必然需要分布式事务的支持,查了MSDN知道 .net 2.0 中利用新增的 System.Transactions 命名空间可以简单的实现分布式事务:

None.gifSystem.Transactions 基础结构通过支持在 SQL Server、ADO.NET、MSMQ 和 Microsoft 分布式事务协调器 (MSDTC) 中启动的事务,使事务编程在整个平台上变得简单和高效。它提供基于 Transaction 类的显式编程模型,还提供使用 TransactionScope 类的隐式编程模型,在这种模型中事务是由基础结构自动管理的。强烈建议使用更为方便的隐式模型进行开发。
具体参考:http://msdn2.microsoft.com/zh-cn/library/system.transactions(VS.80).aspx 以及相关的连接都提供了非常详细的信息

参考MSDN的Demo做了SQL Server 2000 的 使用事务范围实现隐式事务测试,事务可以正常提交以及回滚:
ContractedBlock.gifExpandedBlockStart.gif
None.gifprivate void Test1()
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
InBlock.gif        
// 使用事务范围实现隐式事务
InBlock.gif        
// ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.chs/dv_fxtransactions/html/1ddba95e-7587-48b2-8838-708c275e7199.htm
InBlock.gif

ExpandedSubBlockStart.gifContractedSubBlock.gif        
using (TransactionScope ts = new TransactionScope()) dot.gif{
InBlock.gif            
//Create and open the SQL connection.  The work done on this connection will be a part of the transaction created by the TransactionScope
InBlock.gif
            SqlConnection myConnection = new SqlConnection("server=(local);Integrated Security=SSPI;database=northwind");
InBlock.gif            SqlCommand myCommand 
= new SqlCommand();
InBlock.gif            myConnection.Open();
InBlock.gif            myCommand.Connection 
= myConnection;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (!chkGenError.Checked) dot.gif{
InBlock.gif                
//Restore database to near it's original condition so sample will work correctly.
InBlock.gif
                myCommand.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)";
InBlock.gif                myCommand.ExecuteNonQuery();
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
//Insert the first record.
InBlock.gif
            myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')";
InBlock.gif            myCommand.ExecuteNonQuery();
InBlock.gif
InBlock.gif            
//Insert the second record.
InBlock.gif
            myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')";
InBlock.gif            myCommand.ExecuteNonQuery();
InBlock.gif
InBlock.gif            myConnection.Close();
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (chkCommit.Checked) dot.gif{
InBlock.gif                ts.Complete();
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            
/**/////Call complete on the TransactionScope or not based on input
InBlock.gif            //ConsoleKeyInfo c;
InBlock.gif            
//while (true) {
InBlock.gif            
//    Console.Write("Complete the transaction scope? [Y|N] ");
InBlock.gif            
//    c = Console.ReadKey();
InBlock.gif            
//    Console.WriteLine();
InBlock.gif
InBlock.gif            
//    if ((c.KeyChar == 'Y') || (c.KeyChar == 'y')) {
InBlock.gif            
//        // Commit the transaction
InBlock.gif            
//        ts.Complete();
InBlock.gif            
//        break;
InBlock.gif            
//    }
InBlock.gif            
//    else if ((c.KeyChar == 'N') || (c.KeyChar == 'n')) {
InBlock.gif            
//        break;
InBlock.gif            
//    }
InBlock.gif            
//}
ExpandedSubBlockEnd.gif
        }

ExpandedBlockEnd.gif    }

None.gif
None.gif    
private void Test2()
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
InBlock.gif        
string connectString1 = "server=(local);Integrated Security=SSPI;database=northwind";
InBlock.gif        
string connectString2 = "server=(local);Integrated Security=SSPI;database=pubs";
InBlock.gif        
string dt = DateTime.Now.ToString();
ExpandedSubBlockStart.gifContractedSubBlock.gif        
using (TransactionScope transScope = new TransactionScope()) dot.gif{
InBlock.gif            
using (SqlConnection connection1 = new
ExpandedSubBlockStart.gifContractedSubBlock.gif               SqlConnection(connectString1)) 
dot.gif{
InBlock.gif                
// Opening connection1 automatically enlists it in the 
InBlock.gif                
// TransactionScope as a lightweight transaction.
InBlock.gif
                connection1.Open();
InBlock.gif
InBlock.gif                
// Do work in the first connection.
InBlock.gif
                SqlCommand command1 = new SqlCommand();                
InBlock.gif                command1.Connection 
= connection1;
InBlock.gif
InBlock.gif                
//Restore database to near it's original condition so sample will work correctly.
InBlock.gif
                command1.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)";
InBlock.gif                command1.ExecuteNonQuery();
InBlock.gif
InBlock.gif                
//Insert the first record.
InBlock.gif
                command1.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')";
InBlock.gif                command1.ExecuteNonQuery();
InBlock.gif
InBlock.gif                
//Insert the second record.
InBlock.gif
                command1.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')";
InBlock.gif                command1.ExecuteNonQuery();
InBlock.gif
InBlock.gif                
// Assumes conditional logic in place where the second
InBlock.gif                
// connection will only be opened as needed.
InBlock.gif
                using (SqlConnection connection2 = new
ExpandedSubBlockStart.gifContractedSubBlock.gif                    SqlConnection(connectString2)) 
dot.gif{
InBlock.gif                    
// Open the second connection, which enlists the 
InBlock.gif                    
// second connection and promotes the transaction to
InBlock.gif                    
// a full distributed transaction. 
InBlock.gif
                    connection2.Open();
InBlock.gif                   
InBlock.gif                    
// Do work in the second connection.
InBlock.gif
                    SqlCommand command2 = new SqlCommand();                    
InBlock.gif                    command2.Connection 
= connection2;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
if (!chkGenError.Checked) dot.gif{
InBlock.gif                        
//Restore database to near it's original condition so sample will work correctly.
InBlock.gif
                        command2.CommandText = "DELETE FROM stores WHERE (stor_id = '9797') OR (stor_id = '9798')";
InBlock.gif                        command2.ExecuteNonQuery();
ExpandedSubBlockEnd.gif                    }

InBlock.gif
InBlock.gif                    
//Insert the first record.
InBlock.gif
                    command2.CommandText = "Insert into stores (stor_id, stor_name) VALUES ('9797', 'ebay')";
InBlock.gif                    command2.ExecuteNonQuery();
InBlock.gif
InBlock.gif                    
//Insert the second record.
InBlock.gif
                    command2.CommandText = "Insert into stores (stor_id, stor_name) VALUES ('9798', 'amazon')";
InBlock.gif                    command2.ExecuteNonQuery();                    
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

InBlock.gif            
//  The Complete method commits the transaction.
ExpandedSubBlockStart.gifContractedSubBlock.gif
            if (chkCommit.Checked) dot.gif{
InBlock.gif                transScope.Complete();
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }

None.gif
None.gif    
private void Test3()
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
InBlock.gif        
string connectString1 = "server=(local);Integrated Security=SSPI;database=northwind";
InBlock.gif        
string connectString2 = "server=(local);Integrated Security=SSPI;database=pubs";
InBlock.gif        
string dt = DateTime.Now.ToString();
ExpandedSubBlockStart.gifContractedSubBlock.gif        
using (TransactionScope transScope = new TransactionScope()) dot.gif{
InBlock.gif            
using (SqlConnection connection1 = new
ExpandedSubBlockStart.gifContractedSubBlock.gif               SqlConnection(connectString1)) 
dot.gif{
InBlock.gif                
// Opening connection1 automatically enlists it in the 
InBlock.gif                
// TransactionScope as a lightweight transaction.
InBlock.gif
                connection1.Open();
InBlock.gif
InBlock.gif                
// Do work in the first connection.
InBlock.gif
                SqlCommand command1 = new SqlCommand();
InBlock.gif                command1.Connection 
= connection1;
InBlock.gif
InBlock.gif                
//Restore database to near it's original condition so sample will work correctly.
InBlock.gif
                command1.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)";
InBlock.gif                command1.ExecuteNonQuery();
InBlock.gif
InBlock.gif                
//Insert the first record.
InBlock.gif
                command1.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')";
InBlock.gif                command1.ExecuteNonQuery();
InBlock.gif
InBlock.gif                
//Insert the second record.
InBlock.gif
                command1.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')";
InBlock.gif                command1.ExecuteNonQuery();
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
// Assumes conditional logic in place where the second
InBlock.gif            
// connection will only be opened as needed.
InBlock.gif
            using (SqlConnection connection2 = new
ExpandedSubBlockStart.gifContractedSubBlock.gif                SqlConnection(connectString2)) 
dot.gif{
InBlock.gif                
// Open the second connection, which enlists the 
InBlock.gif                
// second connection and promotes the transaction to
InBlock.gif                
// a full distributed transaction. 
InBlock.gif
                connection2.Open();
InBlock.gif
InBlock.gif                
// Do work in the second connection.
InBlock.gif
                SqlCommand command2 = new SqlCommand();
InBlock.gif                command2.Connection 
= connection2;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                
if (!chkGenError.Checked) dot.gif{
InBlock.gif                    
//Restore database to near it's original condition so sample will work correctly.
InBlock.gif
                    command2.CommandText = "DELETE FROM stores WHERE (stor_id = '9797') OR (stor_id = '9798')";
InBlock.gif                    command2.ExecuteNonQuery();
ExpandedSubBlockEnd.gif                }

InBlock.gif
InBlock.gif                
//Insert the first record.
InBlock.gif
                command2.CommandText = "Insert into stores (stor_id, stor_name) VALUES ('9797', 'ebay')";
InBlock.gif                command2.ExecuteNonQuery();
InBlock.gif
InBlock.gif                
//Insert the second record.
InBlock.gif
                command2.CommandText = "Insert into stores (stor_id, stor_name) VALUES ('9798', 'amazon')";
InBlock.gif                command2.ExecuteNonQuery();
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
//  The Complete method commits the transaction.
ExpandedSubBlockStart.gifContractedSubBlock.gif
            if (chkCommit.Checked) dot.gif{
InBlock.gif                transScope.Complete();
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }
    
None.gif
 
测试的时候需要在 Sql Server 服务管理器中开启 MSDTC,我是再 SQL 2k上做的测试,2k5上应该得到更好的支持。
方法 Test1() 是单数据库的事务,只是为了测试;
 Test2()和Test3() 没有实质区别,都是自动注册事务。
完整代码下载:/Files/Jinglecat/DTCSQL.rar

同时我也尝试了一个Oracle版本,Oracle 10g 2,其中数据库orcl 是默认的启动数据库,而数据库nhrs是我自己建的一个数据库,测试通过,代码跟SQL没有两样,之前网上查到有网友说OracleClient还不支持 MSDTC,查了很多资料,确实在 ado.net 1.x 有问题,现在可以确信 ado.net 2.0 已经可以支持。
完整代码下载:/Files/Jinglecat/DTCORA.rar

现在银杏事务已经可以满数项目需求了,有时间再多更多的研究了^_^

转载于:https://www.cnblogs.com/Jinglecat/archive/2007/04/07/704297.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/436528.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转】OData的初步认识

What – OData是什么? OData - Open Data Protocol,是一个设计和使用RESTful API的标准。REST本身只是一个构建web服务的思想和理念,其没有规定一个统一的标准来限制开发人员该如何设计RESTful API。其实我们实际开发中的确也没有遵循某个统…

选择Windows CE wince嵌入式操作系统 的十大理由

Windows CE是什么? Windows CE是一个具有战略意义的操作系统。它拥有windows操作系统的特点,支持32位虚拟内存机制、按需分配内存和内存映射文件;他也是抢先式多任务并具有强大通信能力的Win32嵌入式操作系统,是微软专门为信息设…

三元运算符 在数据绑定中的使用

在使用 datalist 等控件绑定前台数据的时候&#xff0c;有时希望一行只显示定长字符&#xff0c;多出来的部分以省略号代替&#xff0c;我使用三元运算符来做&#xff1a;<asp:DataList id"DataList1"runat"server"RepeatColumns"5"Width&quo…

【转】ABP源码分析四十三:ZERO的本地化

ABP Zero模块扩展了ABP基础框架中的本地化功能&#xff0c;实现了通过数据库对本地化功能进行管理。其通过数据库保存本地化语言及其资源。 ApplicationLanguage&#xff1a;代表本地化语言的实体类。一种语言就是一个ApplicationLanguage实例。 ApplicationLanguageProvider&a…

WinCE流设备驱动简介及GPIO驱动的实现

作者&#xff1a;ARM-WinCE 流设备驱动实际上就是导出标准的流接口函数的驱动&#xff0c;这是文档上面的定义。在WinCE中&#xff0c;所有的流设备都导出流设备接口&#xff0c;这样WinCE中的Device Manager可以加载和管理这些流设备驱动。 流设备驱动的架构如图&#xff1a;…

计算机出现蓝屏怎么解决,电脑出现蓝屏故障0x00000019怎么办?

原标题&#xff1a;电脑出现蓝屏故障0x00000019怎么办&#xff1f;电脑开机出现蓝屏故障0x00000019怎么处理&#xff1f;电脑出现蓝屏&#xff0c;一般都会有提示错误代码或者出错的文件名等&#xff0c;最近就有用户跟小编反映&#xff0c;开机出现了蓝屏故障&#xff0c;提示…

【转】ABP源码分析四十五:ABP ZERO中的EntityFramework模块

AbpZeroDbContext&#xff1a;配置ABP.Zero中定义的entity的Dbset EntityFrameworkModelBuilderExtensions:给PrimitivePropertyConfiguration添加了扩展方法用于创建Index。 AbpZeroDbModelBuilderExtensions&#xff1a;给DbModelBuilder添加了扩展方法用于表的重命名。 AbpZ…

WinCE中串口驱动及接口函数介绍

作者&#xff1a;ARM-WinCE 在WinCE中&#xff0c;串口驱动实际上就是一个流设备驱动,具体架构如图&#xff1a; 串口驱动本身分为MDD层和PDD层。MDD层对上层的Device Manager提供了标准的流设备驱动接口(COM_xxx)&#xff0c;PDD层实现了HWOBJ结构及结构中若干针对于串口硬件操…

【转】ABP源码分析四十六:ABP ZERO中的Ldap模块

通过AD作为用户认证的数据源。整个管理用户认证逻辑就在LdapAuthenticationSource类中实现。 LdapSettingProvider&#xff1a;定义LDAP的setting和提供DefautValue。主要提供配置访问AD数据库的账号信息。 LdapSettings/ILdapSettings:通过settingManager获取LDAP settings Ab…

广州.NET俱乐部 VSTS活动报道

首先要感谢广州.NET开发人员一直以来对俱乐部的支持&#xff0c;另外&#xff0c;要感谢微软鞠海洋提供的丰富礼品。本次活动主线是VSTS&#xff0c;俱乐部的讲师黎波为我们讲解了VSTS的基本组成和功能分布&#xff0c;让我们大家从宏观上了解VSTS。在活动上&#xff0c;微软的…

【转】ABP源码分析四十七:ABP中的异常处理

ABP 中异常处理的思路是很清晰的。一共五种类型的异常类。 AbpInitializationException用于封装ABP初始化过程中出现的异常&#xff0c;只要抛出AbpInitializationException异常就可以&#xff0c;无须做额外处理。这类异常往往是需要维护人员介入分析的。 其他四个异常都在A…

当你累了,准备放弃时,看看这个吧!!!

在别的空间看到这篇文章&#xff0c;感觉说的很有道理&#xff0c;故转过来&#xff0c;送给所有还在坚持的朋友~~ 每个人都背负着一个沉重的十字架&#xff0c;在缓慢而艰难地朝着目的地前进。 途中&#xff0c;有一个人忽然停了下来。 他心想&#xff1a;这个十字架实在是…

梦游4k

本来还打算晚上看案例分析的&#xff0c; 觉得是在太困了就上床眯会儿&#xff0c; 一睁眼&#xff0c;呀&#xff0c;怎么就快九点了呢。 可怜我一晚上的宝贵时间就这么被我浪费过去了。 从床上蠕动到椅子上&#xff0c;努力扒开眼睛看看BBS&#xff0c; 还是跑步好啊。 跑步好…

ajax里绑定框,Select级联菜单,用Ajax获取Json绑定下拉框(jQuery)

需求类似这样 ↓ ↓ ↓--》 菜单A发生变化&#xff0c;动态取数据填充下拉菜单B。JS代码如下&#xff1a;$(function () {$("#TeamSelect").change(function () {var tid $("#TeamSelect option:selected").val();$.ajax({url: "/ajax/ajaxGetMa…

【转】CANOPEN总线的相关问题点整理分享*****

CANopen 是一个基于 CAN&#xff08;控制局域网&#xff09;串行总线系统和 CAL&#xff08;CAN 应用层&#xff09;的高层协议。CANopen 通讯协议 CiA DS-301 包括周期和事件驱动型通讯&#xff0c;不仅能够将总线负载减少到最低限度&#xff0c;而且还能确保极短的反应时间。…

WinCE系统字体的设置

作者&#xff1a;ARM-WinCE 确实很久没有写Blog了&#xff0c;感觉有些对不住曾经看我blog的朋友。刚从美国回来&#xff0c;由于项目原因&#xff0c;春节都在美国工作&#xff0c;现在有点时间&#xff0c;先写一篇简单的&#xff0c;介绍一下WinCE字体的设置。 WinCE系统字体…

js脚本点击按钮显示文字_JSBOX脚本聊天神器

聊天神器是一个基于JSBox的脚本JSBox 是一个可以用来运行 JavaScript 脚本的 iOS 应用&#xff0c;你可以通过他来执行标准的 JavaScript 脚本 这种执行不是指跑在浏览器上&#xff0c;而是执行在一个完全原生的环境&#xff0c;效率很高。并且我们提供了很多 iOS 原生的接口&a…

轻松实现无刷新三级联动菜单[VS2005与AjaxPro]

最近做一些网站程序&#xff0c;经常要用到多个下拉菜单选择&#xff0c;看了介绍开始用AjaxPro这个控件&#xff0c;感觉效果不错。以前使用过MagicAjax&#xff0c;很久不用了忘记了&#xff0c;最麻烦的就是在虚拟目录的时候比较麻烦&#xff0c;呵呵&#xff0c;在网上也有…

【转】为什么博士叫PhD?

作者&#xff1a;李青影 链接&#xff1a;https://www.zhihu.com/question/20950602/answer/1028008012 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 在填学历的时候遇到过这个问题&#xff0c;明明毕业证书上写…

dnf服务器合并信息,卤蛋带你看韩服!全体服务器合并改版信息互通

‍各位好久不见啊&#xff01;我是卤蛋 本期为各位介绍韩服合区后的全部改动~在韩服合并服务器之前 一共有八个服务器&#xff1a;但是在合区之后大区依然存在&#xff0c;不过服务器是互通的在哪个大区创建角色基本上没什么区别 这样做避免了角色混乱的问题如何切换频道呢&…