前言:关于分布式事务话题一直是颇有争议的话题,在本文中通过ActiveMq 实现分布式事务做一个简单的demo;同时也让自己能在实践中可以获取经验和对分布式事务自己的一些思考。

1.本地事务

我们通常只需借助开发平台中特有数据访问技术和框架(例如Spring、JDBC、ADO.NET),结合关系型数据库自带的事务管理机制来实现事务性的需求。例如A给B转账100元并发送100代金券,不管是服务器挂掉还是转账失败抛出异常,我们最终都要保证这个流程要么都成功要么都失败,否则会出现数据异常。

   2.分布式事务

余额表和代金券表分布在不同的节点的数据库,转账和发放代金券是不同的应用,它们之间通信可能通过rpc,httpclient,mq;假设这时候A服务给B转账成功,但是发放代金券失败,我们应该如何处理呢?笔者在现在公司项目里就有很多这样的问题,我们是和第三方经常有数据交互,那么调用第三方的接口进行划拨操作,有可能在第三方划拨成功但是消息丢失(网络异常、服务器挂掉、某些人新加的不合理代码导致异常回滚等等)

   3.使用消息队列ActiveMq实现事务一致性

  • 以下 demo简单模拟用户注册后发放代金券这一过程;流程首先是用户注册成功后推送用户信息到Active mq,代金券应用中也配置好了Active Mq,但是它是充当消费者的角色,实现代金券消息监听,当监听到消息后会拉取Active Mq的消息发执行派发金券动作; 其中用户注册是一个应用,发放代金券是另外一个应用,它们之间是通过activemq实现消息收发。
  • 首先创建2个maven项目,分别叫account和voucher,在这里我用的是springmvc+jdbc作为项目骨架。
  • 在account项目中我新首先建了一个UserController.java作为注册的控制层,并提供注册的方法,如下代码示例,其中注意的是增加了一张消息表,关于为什么需要消息表下面会详细解答。
  •  package com.zdd.mvc;
    
     import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.jms.core.MessageCreator;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.ModelMap;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    import utils.ActiveMQutil;
    import utils.JdbcUtil;
    import utils.Result; import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.Session; /**
    * Created by dada on 2017/8/25.
    */
    @Controller
    @RequestMapping("/register")
    public class UserAccountController { @Autowired
    private JmsTemplate jmsTemplate; @RequestMapping(method = RequestMethod.GET)
    public String register() {
    return "register";
    } @RequestMapping(method = RequestMethod.POST,value = "/doReg")
    @ResponseBody
    public Result doReg(final String phone) {
    JdbcUtil jdbcUtil = null;
    try{
    jdbcUtil = new JdbcUtil();
    jdbcUtil.getConnection(); jdbcUtil.setAutoCommit(false);
       //往账户表添加一条数据
    String sql = "insert into account(phone) values ('"+phone+"')";
    int row = jdbcUtil.insert(sql);
    if(row == 1){
    //插入到消息记录表
    sql = "insert into message(phone,status) values ('"+phone+"',0)";
    int m_row = jdbcUtil.insert(sql);
    if(m_row == 1){
    //成功后发送队列
    jmsTemplate.send("voucher_message", new MessageCreator() {
    @Override
    public Message createMessage(Session session) throws JMSException {
    return session.createTextMessage(phone);
    }
    });
    }
    }
    jdbcUtil.Commit(); }catch (RuntimeException e){
    e.printStackTrace();
    jdbcUtil.rollback();//出现异常事务回滚
    }finally {
    if(null != jdbcUtil){
    jdbcUtil.releaseConn();
    }
    }
    Result result = new Result();
    return result;
    } }

    消息表主要用处是:  

  •   假如我们消息投递到消息中间件后,消费者那边出现异常,虽然信息已经被消费者消费了,但由于代码或宕机导致消费端数据事务没有成功提交,如果没有消息表,我们将会丢失这一条数据。有了消息表后我们可以查询到有哪些是属于未成功派发的数据,这时候可以通过轮询或者是其他方式再次把这批未成功消费的数据重新派发出去。

  • 根据上述代码及注释,我们来分析下可能的情况:

    1. 操作数据库成功,向MQ中投递消息也成功,皆大欢喜。

    2. 操作数据库失败,不会向MQ中投递消息了。

    3. 操作数据库成功,但是向MQ中投递消息时失败,向外抛出了异常,刚刚执行的更新数据库的操作将被回滚。

    4. 操作数据库成功,投递MQ消息成功,消费异常,数据未更新,通过扫描消息表再次把数据取出进行消费。

    从上面分析的几种情况来看,貌似问题都不大的。那么我们来分析下消费者端面临的问题:

    1. 消息出列后,消费者对应的业务操作要执行成功。如果业务执行失败,消息不能失效或者丢失。需要保证消息与业务操作一致。

    2. 尽量避免消息重复消费,消费前先查询一下是否消费成功,一定要有一个标识标明,如果重复消费,也不能因此影响业务结果,保证幂等性。

借用其他人的时序图:

【原】ActiveMq实现分布式事务一致性的更多相关文章

  1. 六:分布式事务一致性协议paxos的分析

    最近研究paxos算法,看了许多相关的文章,概念还是很模糊,觉得还是没有掌握paxos算法的精髓,所以花了3天时间分析了libpaxos3的所有代码,此代码可以从https://bitbucket.o ...

  2. 三:分布式事务一致性协议2pc和3pc

    一:分布式一致性协议--->对于一个分布式系统进行架构设计的过程中,往往会在系统的可用性和数据一致性之间进行反复的权衡,于是就产生了一系列的一致性协议.--->长期探索涌现出一大批经典的一 ...

  3. Dubbo 分布式事务一致性实现

    我觉得事务的管理不应该属于Dubbo框架, Dubbo只需实现可被事务管理即可, 像JDBC和JMS都是可被事务管理的分布式资源, Dubbo只要实现相同的可被事务管理的行为,比如可以回滚, 其它事务 ...

  4. 五:分布式事务一致性协议paxos的应用场景

    1.应用场景 (1)分布式中的一致性 Paxos算法主要是解决一致性问题,关于“一致性”,在不同的场景有不同的解释: NoSQL领域:一致性更强调“能读到新写入的”,就是读写一致性数据库领域:一致性强 ...

  5. 四:分布式事务一致性协议paxos通俗理解

    转载地址:http://www.lxway.com/4618606.htm 维基的简介:Paxos算法是莱斯利·兰伯特(Leslie Lamport,就是 LaTeX 中的"La" ...

  6. 分布式事务 spring 两阶段提交 tcc

    请问分布式事务一致性与raft或paxos协议解决的一致性问题是同一回事吗? - 知乎 https://www.zhihu.com/question/275845393 分布式事务11_TCC 两阶段 ...

  7. 分布式事务(四)之TCC

    在电商领域等互联网场景下,传统的事务在数据库性能和处理能力上都暴露出了瓶颈.在分布式领域基于CAP理论以及BASE理论,有人就提出了柔性事务的概念.在业内,关于柔性事务,最主要的有以下四种类型:两阶段 ...

  8. 一文教你迅速解决分布式事务 XA 一致性问题

    欢迎大家前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~ 作者:腾讯云数据库团队 近日,腾讯云发布了分布式数据库解决方案(DCDB),其最明显的特性之一就是提供了高于开源分布式事务XA的性能.大型 ...

  9. 使用kafka消息队列解决分布式事务(可靠消息最终一致性方案-本地消息服务)

    微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务 本文转自:http://skaka.me/blog/2016/04/21/springcloud1/ 不同于单一 ...

随机推荐

  1. java易错题

    (选择二项) 8 A: B: C: D: (选择一项) 9 A: B: C: D: 正确答案是 A 您回答的是 B 回答错误 正确答案是 B,D 您回答的是 A,C 回答错误 (选择一项) 18 A: ...

  2. Paper | Batch Normalization

    目录 1. PROBLEM 1.1. Introduction 1.2. Analysis 2. SOLUTION 2.1. Batch Normalization 及其问题 2.2. 梯度修正及其问 ...

  3. Linux 根据PID找到相应应用程序的运行目录

    1.找到运行程序的PID # ps aux | grep redis root pts/ S+ : : grep redis root ? Ssl Aug30 : redis-server *: # ...

  4. uniGUI日志的控制

    uniGUI日志的控制 (2015-10-12 08:30:29) 转载▼ 标签: unigui 分类: uniGUI uniGUI本身提供了日志功能,利用uniServerModule.Server ...

  5. [数据清洗]-Pandas 清洗“脏”数据(一)

    概要 准备工作 检查数据 处理缺失数据 添加默认值 删除不完整的行 删除不完整的列 规范化数据类型 必要的转换 重命名列名 保存结果 更多资源 Pandas 是 Python 中很流行的类库,使用它可 ...

  6. 库函数wordcloud安装的问题

    在对python有了一定的了解之后就对python的第三方库产生了十分浓厚的兴趣,因为python的很多功能都是要依靠第三方库函数来实现的,而且在计算机二级刚刚加入的python考试中也有对第三方库的 ...

  7. [UWP]缓存Lottie动画帧

    在上一篇博文<[UWP]在UWP平台中使用Lottie动画>中我简单介绍了一下LottieUWP项目以及如何使用它呈现Lottie动画,这篇文章里我们来讲点进阶的东西--缓存Lottie动 ...

  8. KMP string pattern matching

    The function used here is from the leetcode. Details can be found in leetcode problem: Implement str ...

  9. STL详解

    STL概貌                                                                                                ...

  10. javascript从作用域到闭包-笔记

    读<你不知道的javascript>一书做个笔记;编译原理:    js是一门编译型的语言,与传统编译语言类似,传统编译的过程分为三个阶段 ;     1. 分词/词法分析; 2.解析/语 ...