前言:关于分布式事务话题一直是颇有争议的话题,在本文中通过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. noip第17课资料

  2. JDBC创建链接的几种方式

    首先,使用java程序访问数据库的前提 数据库的主机地址(ip地址) 端口 数据库用户名 数据库用户密码 连接的数据库 代码: private static String url = "jd ...

  3. Instruments Time Profiler时,无法定位代码,如何破?

    都是地址符号,往深里也一直是地址符号,根本没法判断是哪些代码的执行时间 解决办法: 选下面的.

  4. 使用Docker搭建CentOS 7 + Apache 2.4+ PHP7

    从Docker Hub上Pull最新的CentOS 7镜像并新建容器 # sudo docker pull centos docker run -p 8082:80 --name centos_c - ...

  5. Windows 系统 IP 和端口的相关检测命令

    查看本机IP地址 查看自己电脑的ip,使用 ipconfig 命令 ipconfig 检测指定IP是否联通 检测某个ip是否可以连通,直接使用 ping 命令 ping 219.148.111.212 ...

  6. Appium发送中文或其他语言的问题

    1. 需要在配置信息中增加'unicodeKeyboard' = “True”字段,如下: def driver_weixin(platformVersion="6.0.1",de ...

  7. Spring Boot Runner启动器

    Runner启动器 如果你想在Spring Boot启动的时候运行一些特定的代码,你可以实现接口ApplicationRunner或者CommandLineRunner,这两个接口实现方式一样,它们都 ...

  8. Python——使用代码平台进行识别验证码

    打码平台介绍 一般使用超级鹰或打码兔的打码平台. 超级鹰介绍 打开http://www.chaojiying.com/contact.html注册用户,生成软件ID 下载python的demo文件 查 ...

  9. 自动化测试 selenium 环境搭建

    做 web 项目,测试是无法避免的.对于某些特定功能,采用单元测试就行.但如果想对网站进行整体测试,人工点击测试可行但有点累,如果能借助自动化测试工具就更好了.selenium 就是一款能满足这样要求 ...

  10. [EXP]Drupal < 8.5.11 / < 8.6.10 - RESTful Web Services unserialize() Remote Command Execution (Metasploit)

    ## # This module requires Metasploit: https://metasploit.com/download # Current source: https://gith ...