.NET分布式事务处理总结【下】 - 包含MSMQ的分布式事务处理

转自:http://www.cnblogs.com/daxnet/archive/2011/03/15/1984995.html

.NET直接提供对MSMQ的访问支持,只需要添加System.Messaging程序集引用即可方便地操作MSMQ。MSMQ支持两种事务处理模式:内部事务处理以及基于MS-DTC的分布式事务处理。

MSMQ的内部事务处理

MSMQ的内部事务处理是指,仅采用MSMQ本身提供的事务处理机制完成事务处理。比如,假设有一系列的消息需要发布到MSMQ,那么,就可以启动一个内部事务,确保这些消息的发布过程是一个原子操作。要使用MSMQ的内部事务处理机制,在创建消息队列的时候,就需要勾选“事务性”选项,如下图所示:

首先,需要创建一个MessageQueueTransaction的对象,并使用Begin调用以启动MSMQ的内部事务处理。然后,在MessageQueue的Send方法中,使用Send(object, MessageQueueTransaction)的重载函数发送消息,将创建好的MessageQueueTransaction对象作为第二个参数传递给Send方法;在完成所有消息的发送之后,使用MessageQueueTransaction对象的Commit方法提交事务。如果在发送消息的过程中遇到问题,则使用MessageQueueTransaction对象的Abort调用回滚事务。请参见下面的示例代码:

隐藏行号 复制代码 ?MSMQ的内部事务处理

  1. using (MessageQueue messageQueue = new MessageQueue(@".\private$\TPCDemoQueue",
    
  2.     false, false, QueueAccessMode.SendAndReceive))
    
  3. {
    
  4.     MessageQueueTransaction trans = new MessageQueueTransaction();
    
  5.     try
    
  6.     {
    
  7.         trans.Begin();
    
  8.         for (int i = 0; i < 5; i++)
    
  9.         {
    
  10.             messageQueue.Send(new Message(i), trans);
    
  11.         }
    
  12.         trans.Commit();
    
  13.     }
    
  14.     catch
    
  15.     {
    
  16.         trans.Abort();
    
  17.     }
    
  18.     messageQueue.Close();
    
  19. }
    
  20. 
    

注意:如果你的消息队列在创建的时候没有设置“事务性”选项,那么,在完成消息队列的创建以后,你将无法修改该选项。更糟糕的是,在非事务性队列上执行上面的代码,则无法将消息发布到消息队列上,框架本身也不会提示任何错误信息,指示消息并未发布成功。

在分布式事务处理中使用MSMQ

在分布式事务处理的上下文中(比如,.NET 2.0+的TransactionScope中),上面所提到的MessageQueueTransaction将毫无用处,也就是说,MessageQueueTransaction与分布式事务处理毫无关系。你所要做的是,用正常的方式初始化一个MessageQueue的实例,然后,调用Send方法发布消息,在发布消息的时候,通过设置MessageQueueTransactionType的值来告诉MessageQueue,目前正处于一个分布式事务的上下文中。于是,你需要使用Send/Receive的重载方法:Send(object, MessageQueueTransactionType)以及Receive(MessageQueueTransactionType)。如下:

隐藏行号 复制代码 ?分布式事务中的MSMQ调用

  1. using (TransactionScope transaction = new TransactionScope())
    
  2. {
    
  3.     Message inputMsg = inputQueue.Receive(MessageQueueTransactionType.Automatic);
    
  4.     // do some work
    
  5.     transaction.Complete();
    
  6. }
    
  7. 
    

注意:对于一些生命周期相对较长的事务处理,比如,假设你的用例是这样的:你首先需要从一个消息队列中获得消息,然后更新你的数据库记录,那么你的代码可能会是这样的:

隐藏行号 复制代码 ?分布式事务中的MSMQ调用

  1. using (TransactionScope transaction = new TransactionScope())
    
  2. {
    
  3.     using (MessageQueue someQueue = new MessageQueue("<queue connection>"))
    
  4.     {
    
  5.         Message msg = someQueue.Receive();
    
  6.         // do something else
    
  7.     }
    
  8.     transaction.Complete();
    
  9. }
    
  10. 
    

这样做其实是不对的!因为Receive方法是一种同步调用,如果消息队列中根本没有任何内容,那么Receive调用就会被阻塞,直到消息队列中出现新的消息。这就意味着你的分布式事务一直都是处于开启的状态,而且可能由于等待时间过长而导致超时,最终导致一个MessageQueueException。

正确的做法是,在MessageQueue上使用BeginPeek调用(注意:不是BeginReceive方法,因为BeginReceive方法并不是用来处理事务性队列的),然后订阅PeekComplete事件,在事件处理过程中,再使用TransactionScope以及Receive等方法实现消息的获取。例如:

隐藏行号 复制代码 ?分布式事务中的MSMQ调用

  1. MessageQueue inputQueue = new MessageQueue("<queue connection>");
    
  2. inputQueue.PeekCompleted += (s, e) =>
    
  3.     {
    
  4.         using (TransactionScope transaction = new TransactionScope())
    
  5.         {
    
  6.             Message inputMsg = inputQueue.Receive(MessageQueueTransactionType.Automatic);
    
  7.             // do some work
    
  8.             transaction.Complete();
    
  9.         }
    
  10.         inputQueue.BeginPeek();
    
  11.     };
    
  12. inputQueue.BeginPeek();
    
  13. 
    

最后再提醒一下,就是如果你所要做的事情仅限于与MSMQ打交道,那么只要使用MSMQ的内部事务处理机制就可以了,毕竟使用分布式事务处理会涉及到MS-DTC,从而造成过大的系统开销,影响性能。

时间: 2024-08-28 23:44:20

.NET分布式事务处理总结【下】 - 包含MSMQ的分布式事务处理的相关文章

获取一个想要的指定文件的集合,获取文件夹下(包含子目录的所有.java的文件对象,并存储到集合中)

import java.io.File; import java.io.FileFilter; import java.io.ObjectInputStream.GetField; import java.util.ArrayList; import java.util.List; public class huoquwenjian { /*获取一个想要的指定文件的集合,获取文件夹下(包含子目录的所有.java的文件对象,并存储到集合中) * 思路: * 1,既然包含子目录,就需要递归. * 2

windows下单机版的伪分布式solrCloud环境搭建Tomcat+solr+zookeeper

前面简单了解了ZooKeeper的相关知识,为SolrCloud的学习作了一层铺垫.在SolrCloud的wiki中,可以很简单地用jetty实现嵌入式ZooKeeper的单机版SolrCloud.但是在生产环境中,Solr一般都是部署在Tomcat上的.为了使架构更加灵活,ZooKeeper也是单独部署的.日常学习中,就一台单机怎么学习solrCloud呢?本文将记录在win7上实现ZooKeeper+Tomcat版的伪分布式SolrCloud. 1.软件工具箱 在本文的实践中,需要用到以下的

SpringCloud从入门到进阶(四)——生产环境下Eureka的完全分布式部署

内容 由于前两节的内容我们知道,开启了preferIpAddress后,Eureka的伪分布式部署会提示replica不可用.这一节我们讲解如何在生产环境下部署完全分布式的Eureka集群,确保开启了preferIpAddress后replica的可用性. 版本 IDE:IDEA 2017.2.2 x64 JDK:1.8.0_171 manve:3.3.3 SpringBoot:1.5.9.RELEASE SpringCloud:Dalston.SR1 适合人群 Java开发人员 节点信息: 节

【分布式事务】使用atomikos+jta解决分布式事务问题

一.前言 分布式事务,这个问题困惑了小编很久,在3个月之前,就间断性的研究分布式事务.从MQ方面,数据库事务方面,jta方面.近期终于成功了,使用JTA解决了分布式事务问题.先写一下心得,后面的二级提交也会在研究. 二.介绍 分布式事务 说到分布式事务,可以理解为,由于分布式而引起的事务不一致的问题.随着项目做大,模块拆分,数据库拆分.一次包含增删改操作数据库涉及到了更新两个不同物理节点的数据库,这样的数据库事务只能保证自己处理的部分的事务,但是整个的事务就不能保证一致性. 网上针对分布式事务常

分布式数据库中数据的分片----《分布式数据库系统及其应用》

数据分片也称数据分割,是分布式数据库的特征之一.在一个分布式数据库中,全局数据库是由各个局部数据库逻辑组合而成:反之,各个局部数据库是由全局数据库的某种逻辑分割而得. 在分布式数据库中,数据存放的单位是数据的逻辑片段.对关系数据库来说,一个数据库的逻辑片段是关系的一部分.数据分片有三种基本分法,它们是通过关系代数的基本运算来实现的. 水平分片 按特定条件把全局关系的所有元祖分划成若干个相互不相交的子集,每一子集为全局关系的一个逻辑片段,简称片段.它们通过对全局关系施加选择运算得到,并可通过对这些

分布式服务:Dubbo+Zookeeper+Proxy+Restful 分布式架构

分布式 分布式服务:Dubbo+Zookeeper+Proxy+Restful 分布式消息中间件:KafKa+Flume+Zookeeper 分布式缓存:Redis    分布式文件:FastDFS 负载均衡:Keepalived+Nginx+Proxy(三重负载) 愿意了解框架技术或者源码的朋友直接加求求(企鹅):2042849237更多详细源码参考来源:http://minglisoft.cn/technology

什么是分布式锁及正确使用redis实现分布式锁

分布式锁 分布式锁其实可以理解为:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性. 举个不太恰当的例子:假设共享的资源就是一个房子,里面有各种书,分布式系统就是要进屋看书的人,分布式锁就是保证这个房子只有一个门并且一次只有一个人可以进,而且门只有一把钥匙.然后许多人要去看书,可以,排队,第一个人拿着钥匙把门打开进屋看书并且把门锁上,然后第二个人没有钥匙,那就等着,等第一个出来,然后你在拿着钥匙进去,然后就是以此类推 实现原理 互斥性 保证同一时间只有一个客户端可以拿到锁,也就是可

分布式服务框架下,如何做到服务化最佳实践?

“升级服务框架后,性能.可靠性等问题日益明显.服务化之后面临的诸多挑战,怎样分析才能给出实践最优解? 在服务化之前,业务通常都是本地API调用,本地方法调用性能损耗较小.服务化之后,服务提供者和消费者之间采用远程网络通信,增加了额外的性能损耗,业务调用的时延将增大,同时由于网络闪断等原因,分布式调用失败的风险也增大.如果服务框架没有足够的容错能力,业务失败率将会大幅提升. 除了性能.可靠性等问题,跨节点的事务一致性问题.分布式调用带来的故障定界困难.海量微服务运维成本增加等也是分布式服务框架必须

Java事务处理全解析(八)——分布式事务入门例子(Spring+JTA+Atomikos+Hibernate+JMS)

在本系列先前的文章中,我们主要讲解了JDBC对本地事务的处理,本篇文章将讲到一个分布式事务的例子. 请通过以下方式下载github源代码: git clone https://github.com/davenkin/jta-atomikos-hibernate-activemq.git 本地事务和分布式事务的区别在于:本地事务只用于处理单一数据源事务(比如单个数据库),分布式事务可以处理多种异构的数据源,比如某个业务操作中同时包含了JDBC和JMS或者某个操作需要访问多个不同的数据库. Java