前言:关于分布式事务话题一直是颇有争议的话题,在本文中通过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. ubuntu服务器搭建DVWA站点

    把DVWA里面的文件夹拷贝到/var/www/html里面去 1.安装之前先更新系统 sudo apt update 2.安装Apache2 sudo apt install apache2 3.安装 ...

  2. EF6学习笔记(四) 弹性连接及命令拦截调试

    EF6学习笔记总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 本章原文地址:Connection Resiliency and Command Interception 原文 ...

  3. iOS逆向之TheOS

    TheOS 被设计为一个在基于 Unix 平台 (Mac OS X.IOS…) 和大多数 的Linux 平台下开发 iOS 程序的集成开发环境.说是集成开发环境,其实就是给我们准备好了一些代码模板.预 ...

  4. nodejs从http升级到https(阿里云证书的使用)

    升级原因 1.各大搜索引擎中,https的网页的权重比一般的http的网页权重要高. 2.从用户体验的角度,一个老是被浏览器提醒该网页不可信的网页,总不会让用户感到安心 所以将网站从http升级为ht ...

  5. JavaScript实现HTML页面集成QQ空间分享功能

    <!DOCTYPE HTML> <html> <head> <title>QQ空间分享</title> <meta http-equi ...

  6. debian安装tftp服务

    步骤1:安装 apt-get install tftp-hpa tftpd-hpa tftp-hpa是client,tftpd-hpaserver 步骤2:建立tftp目录 mkdir /tftpbo ...

  7. Linux - 查看进程状态

    ps命令 report a snapshot of the current processes. 能提供一份当前进程的快照,以列表的形式显示正在运行的进程. 列出进程的数量取决于命令所附加的参数,例如 ...

  8. python数据结构-数组/列表/栈/队列及实现

    首先 我们要分清楚一些概念和他们之间的关系 数组(array)  表(list)  链表(linked list)  数组链表(array list)   队列(queue)  栈(stack) li ...

  9. maven snapshot和release版本的区别

    Maven的Snapshot版本与Release版本 1. Snapshot版本代表不稳定.尚处于开发中的版本 2. Release版本则代表稳定的版本 3. 什么情况下该用SNAPSHOT? 协同开 ...

  10. 树莓派2B+安装Debain操作系统

    写在前面 本篇文章基于当前树莓派官方最新提供的Debain操作系统进行操作,Linux内核版本 4.14.71.本篇文章内容涵盖SD卡写入官方Debain操作系统,开启SSH连接,修改语言环境,改变当 ...