【原】ActiveMq实现分布式事务一致性
前言:关于分布式事务话题一直是颇有争议的话题,在本文中通过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;
} }消息表主要用处是:
假如我们消息投递到消息中间件后,消费者那边出现异常,虽然信息已经被消费者消费了,但由于代码或宕机导致消费端数据事务没有成功提交,如果没有消息表,我们将会丢失这一条数据。有了消息表后我们可以查询到有哪些是属于未成功派发的数据,这时候可以通过轮询或者是其他方式再次把这批未成功消费的数据重新派发出去。
根据上述代码及注释,我们来分析下可能的情况:
操作数据库成功,向MQ中投递消息也成功,皆大欢喜。
操作数据库失败,不会向MQ中投递消息了。
操作数据库成功,但是向MQ中投递消息时失败,向外抛出了异常,刚刚执行的更新数据库的操作将被回滚。
- 操作数据库成功,投递MQ消息成功,消费异常,数据未更新,通过扫描消息表再次把数据取出进行消费。
从上面分析的几种情况来看,貌似问题都不大的。那么我们来分析下消费者端面临的问题:
消息出列后,消费者对应的业务操作要执行成功。如果业务执行失败,消息不能失效或者丢失。需要保证消息与业务操作一致。
尽量避免消息重复消费,消费前先查询一下是否消费成功,一定要有一个标识标明,如果重复消费,也不能因此影响业务结果,保证幂等性。
借用其他人的时序图:


【原】ActiveMq实现分布式事务一致性的更多相关文章
- 六:分布式事务一致性协议paxos的分析
最近研究paxos算法,看了许多相关的文章,概念还是很模糊,觉得还是没有掌握paxos算法的精髓,所以花了3天时间分析了libpaxos3的所有代码,此代码可以从https://bitbucket.o ...
- 三:分布式事务一致性协议2pc和3pc
一:分布式一致性协议--->对于一个分布式系统进行架构设计的过程中,往往会在系统的可用性和数据一致性之间进行反复的权衡,于是就产生了一系列的一致性协议.--->长期探索涌现出一大批经典的一 ...
- Dubbo 分布式事务一致性实现
我觉得事务的管理不应该属于Dubbo框架, Dubbo只需实现可被事务管理即可, 像JDBC和JMS都是可被事务管理的分布式资源, Dubbo只要实现相同的可被事务管理的行为,比如可以回滚, 其它事务 ...
- 五:分布式事务一致性协议paxos的应用场景
1.应用场景 (1)分布式中的一致性 Paxos算法主要是解决一致性问题,关于“一致性”,在不同的场景有不同的解释: NoSQL领域:一致性更强调“能读到新写入的”,就是读写一致性数据库领域:一致性强 ...
- 四:分布式事务一致性协议paxos通俗理解
转载地址:http://www.lxway.com/4618606.htm 维基的简介:Paxos算法是莱斯利·兰伯特(Leslie Lamport,就是 LaTeX 中的"La" ...
- 分布式事务 spring 两阶段提交 tcc
请问分布式事务一致性与raft或paxos协议解决的一致性问题是同一回事吗? - 知乎 https://www.zhihu.com/question/275845393 分布式事务11_TCC 两阶段 ...
- 分布式事务(四)之TCC
在电商领域等互联网场景下,传统的事务在数据库性能和处理能力上都暴露出了瓶颈.在分布式领域基于CAP理论以及BASE理论,有人就提出了柔性事务的概念.在业内,关于柔性事务,最主要的有以下四种类型:两阶段 ...
- 一文教你迅速解决分布式事务 XA 一致性问题
欢迎大家前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~ 作者:腾讯云数据库团队 近日,腾讯云发布了分布式数据库解决方案(DCDB),其最明显的特性之一就是提供了高于开源分布式事务XA的性能.大型 ...
- 使用kafka消息队列解决分布式事务(可靠消息最终一致性方案-本地消息服务)
微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务 本文转自:http://skaka.me/blog/2016/04/21/springcloud1/ 不同于单一 ...
随机推荐
- python:a+=b 和a=a+b? 基础数据类型也不能乱用
python:a+=b 不等于a=a+b? a+=b 调用的是__iadd__方法,但是a+b调用的是__add__方法.对于自定义的对象,我们通过覆盖两个方法来实现+=和+操作,但是基础数据类型呢? ...
- 20155326刘美岑 Exp6 信息收集与漏洞扫描
20155326刘美岑 Exp6 信息收集与漏洞扫描 实验后回答的问题 (1)哪些组织负责DNS,IP的管理. 全球根服务器均由美国政府授权的ICANN统一管理,负责全球的域名根服务器.DNS和IP地 ...
- The First BoKe
A.如何看待师生关系 说起师生关系,我们每个人都有不同的见解,但无一例外,师者,传道授业解惑也,老师的为学生传授的才能知识,是学生今后发展的宝贵财富,无论是从哪方面,都可以对学生起着积极向上的作用.而 ...
- wampserver 的默认首页设置
# wampserver 首页顺序设置 <IfModule dir_module> DirectoryIndex index.php default.php index.html inde ...
- MVC+EF CODE FIRST的使用
1创建标准MVC项目 2通过NuGet安装EF 3在Models文件夹中编写实体类 4创建EFDB上下文类 5在webconfig中创建连接字符串,其中name=EFDB上下文类名 6通过管理控制台执 ...
- XCode 设置自定义环境变量
XCode 设置自定义环境变量 Product -> Scheme -> Edit Scheme -> 之后设置环境变量.
- 设置Acad2008默认启动 win10设置默认cad2008启动 调试设置.
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\AutoCAD.Drawing.17\shell\open\command]@=&quo ...
- Mac OS 中安装 autoconf 和 automake
在Mac上面编译FFmpeg需要安装很多东西,首先是:autoconf 和 automake 请按照以下顺序安装: curl -O http://mirrors.kernel.org/gnu/m4/m ...
- jQuery的JS库在本地运行项目时提示无法加载
最近公司有个项目在我本地运行时引用本地的jquery.js,浏览器提示无法加载 <script src="/js/newperson/jquery-1.11.3.min.js" ...
- 关于height、offsetheight、clientheight、scrollheight、innerheight、outerheight的区别一览
平时,不管在pc端页面还是移动端页面,因为我们一般很少会设置某个块的的高度,但是呢,我有时候有需要取到这些高度以便于我们方便进行判断和下一步的编写.一般这个时候我都是直接的获取一个块的高度.heigh ...