Springboot整合RocketMQ解决分布式事务
直接上代码:
代码结构如下:

依次贴出相关类:
DataSource1Config:
package com.example.demo.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
/**
* @description: ${description}
* @author: dfz
* @create: 2020-02-24
**/
//DataSource01
@Configuration // 注册到springboot容器中
@MapperScan(basePackages = "com.example.demo.test01", sqlSessionFactoryRef = "test1SqlSessionFactory")
public class DataSource1Config {
@Bean(name = "test1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.test1")
@Primary
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "test1SqlSessionFactory")
@Primary
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
// bean.setMapperLocations(
// new
// PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/test1/*.xml"));
return bean.getObject();
}
@Bean(name = "test1TransactionManager")
@Primary
public DataSourceTransactionManager testTransactionManager(@Qualifier("test1DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "test1SqlSessionTemplate")
@Primary
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
DataSource2Config:
package com.example.demo.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
/**
* @description: ${description}
* @author: dfz
* @create: 2020-02-24
**/
//DataSource2
@Configuration // 注册到springboot容器中
@MapperScan(basePackages = "com.example.demo.test02", sqlSessionFactoryRef = "test2SqlSessionFactory")
public class DataSource2Config {
@Bean(name = "test2DataSource")
@ConfigurationProperties(prefix = "spring.datasource.test2")
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "test2SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
// bean.setMapperLocations(
// new
// PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/test2/*.xml"));
return bean.getObject();
}
@Bean(name = "test2TransactionManager")
public DataSourceTransactionManager testTransactionManager(@Qualifier("test2DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "test2SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
OrderConsumer:
package com.example.demo.consumer;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.entity.DispatcherEntity;
import com.example.demo.entity.OrderEntity;
import com.example.demo.test02.DispatcherMapper;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @description: 消费者
* @author: dfz
* @create: 2020-02-24
**/
@Service
@RocketMQMessageListener(topic = "orderTopic", consumerGroup = "springboot-consumer-group")
public class OrderConsumer implements RocketMQListener<String>{
@Autowired
private DispatcherMapper dispatcherMapper;
@Override
public void onMessage(String msg) {
OrderEntity orderEntity = JSONObject.parseObject(msg, OrderEntity.class);
String orderId = orderEntity.getOrderId();
DispatcherEntity dispatcherEntity = new DispatcherEntity(orderId, "123456");
dispatcherMapper.insertDistribute(dispatcherEntity);
}
}
ProducerController:
package com.example.demo.producer;
import com.example.demo.service.ProducerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @description: ${description}
* @author: dfz
* @create: 2020-02-24
**/
@RestController
public class ProducerController {
@Autowired
private ProducerService producerService;
@RequestMapping(value = "sendMsg")
public String insertUser(){
producerService.saveOrder();
return "success";
}
}
ProducerService:
package com.example.demo.service;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.entity.OrderEntity;
import com.example.demo.test01.OrderMapper;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import java.util.Date;
/**
* @description: ProducerService
* @author: dfz
* @create: 2020-02-24
**/
@Service
public class ProducerService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RocketMQTemplate rocketMQTemplate;
public String saveOrder(){
//提前生成订单id
String orderId = System.currentTimeMillis()+"";
//提前生成半消息,再执行本地事务
OrderEntity orderEntity = creatOrder(orderId);
String msg = JSONObject.toJSONString(orderEntity);
MessageBuilder<String> tMessageBuilder = MessageBuilder.withPayload(msg);
tMessageBuilder.setHeader("msg", msg);
Message message = tMessageBuilder.build();
//该消息不会被消费
rocketMQTemplate.sendMessageInTransaction("springboot-producer-group", "orderTopic", message, null);
return orderId;
}
public OrderEntity creatOrder(String orderId){
OrderEntity orderEntity = new OrderEntity();
orderEntity.setOrderId(orderId);
orderEntity.setOrderName("订单Id1234");
orderEntity.setOrderCreateDate(new Date());
orderEntity.setPrice(300d);
return orderEntity;
}
}
package com.example.demo.listener;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.entity.OrderEntity;
import com.example.demo.test01.OrderMapper;
import com.example.demo.utils.TransactionalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
/**
* @description: ${description}
* @author: dfz
* @create: 2020-02-24
**/
@Slf4j
@Component
@RocketMQTransactionListener(txProducerGroup = "springboot-producer-group")
public class SyncProducerListener implements RocketMQLocalTransactionListener {
@Autowired
private TransactionalUtil transactionalUtil;
@Autowired
private OrderMapper orderMapper;
//执行本地事务
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object o) {
MessageHeaders headers = message.getHeaders();
Object object = headers.get("msg");
if (object == null) {
return RocketMQLocalTransactionState.ROLLBACK;
}
String orderMessage = (String) object;
OrderEntity orderEntity = JSONObject.parseObject(orderMessage, OrderEntity.class);
TransactionStatus status = null;
try {
status = transactionalUtil.begin();
int result = orderMapper.addOrder(orderEntity);
transactionalUtil.commit(status);
if (result < 1) {
return RocketMQLocalTransactionState.ROLLBACK;
}
return RocketMQLocalTransactionState.COMMIT;
} catch (Exception e) {
if (status != null) {
transactionalUtil.rollback(status);
return RocketMQLocalTransactionState.ROLLBACK;
}
}
return null;
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
MessageHeaders headers = message.getHeaders();
Object object = headers.get("msg");
if (object == null) {
return RocketMQLocalTransactionState.ROLLBACK;
}
String orderMessage = (String) object;
OrderEntity orderEntity = JSONObject.parseObject(orderMessage, OrderEntity.class);
String orderId = orderEntity.getOrderId();
//查询数据库
OrderEntity orderEntity1 = orderMapper.findOrder(orderId);
if (null == orderEntity1) {
return RocketMQLocalTransactionState.UNKNOWN;
}
return RocketMQLocalTransactionState.COMMIT;
}
}
package com.example.demo.test01;
import com.example.demo.entity.OrderEntity;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
/**
* @description: ${description}
* @author: dfz
* @create: 2020-02-24
**/
public interface OrderMapper {
@Insert("insert into order values(null,#{order.orderId},#{order.orderName}, #{order.price}, #{order.orderCreateDate});")
public int addOrder(OrderEntity order);
@Insert("select * from order where orderId = ${orderId};")
public OrderEntity findOrder(String orderId);
}
package com.example.demo.test02;
import com.example.demo.entity.DispatcherEntity;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
/**
* @description: ${description}
* @author: dfz
* @create: 2020-02-24
**/
public interface DispatcherMapper {
@Insert("insert into order_users values(null,#{entity.name},#{entity.age});")
public int insertDistribute(DispatcherEntity entity);
}
package com.example.demo.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
/**
* @description: ${description}
* @author: dfz
* @create: 2020-02-24
**/
@Service
public class TransactionalUtil {
@Autowired
public DataSourceTransactionManager transactionManager;
public TransactionStatus begin(){
TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionAttribute());
return transactionStatus;
}
public void commit(TransactionStatus status){
transactionManager.commit(status);
}
public void rollback(TransactionStatus status){
transactionManager.rollback(status);
}
}
package com.example.demo.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @description: ${description}
* @author: dfz
* @create: 2020-02-24
**/
@Data
public class DispatcherEntity implements Serializable {
private String orderId;
private String userId;
public DispatcherEntity(String orderId, String userId) {
this.orderId = orderId;
this.userId = userId;
}
}
package com.example.demo.entity;
import java.io.Serializable;
import java.util.Date;
/**
* @description: ${description}
* @author: dfz
* @create: 2020-02-20
**/
public class OrderEntity implements Serializable{
private String orderId;
private String orderName;
private Date orderCreateDate;
private Double price;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Date getOrderCreateDate() {
return orderCreateDate;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public void setOrderCreateDate(Date orderCreateDate) {
this.orderCreateDate = orderCreateDate;
}
public OrderEntity(String orderId, String orderName) {
this.orderId = orderId;
this.orderName = orderName;
}
public OrderEntity() {
}
}
server.port=8088
###datasource1
spring.datasource.test1.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.test1.jdbc-url = jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.test1.username = root
spring.datasource.test1.password = 123456
###datasource2
spring.datasource.test2.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.test2.jdbc-url = jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.test2.username = root
spring.datasource.test2.password = 123456
rocketmq.name-server=192.168.2.3:9876
rocketmq.producer.group=boot_sync_user
Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example.demo</groupId>
<artifactId>rocketmq-transactional</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>rocketmq-transactional</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!-- mysql 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- springboot-web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- springboot 整合 pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<!--RocketMQ -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.0.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Springboot整合RocketMQ解决分布式事务的更多相关文章
- springboot整合RocketMq(非事务)
1.配置文件 1.yml配置文件 rocketmq: #mq配置 producer: iseffect: true type: default # (transaction,default) tran ...
- springboot整合多数据源解决分布式事务
一.前言 springboot整合多数据源解决分布式事务. 1.多数据源采用分包策略 2.全局分布式事务管理:jta-atomikos. ...
- 搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务
搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务 初步认识RocketMQ的核心模块 rocketmq模块 rocketmq-broker:接受生产者发来的消息并存储(通过调用rocke ...
- RabbitMQ解决分布式事务
案例:经典案例,以目前流行点外卖的案例,用户下单后,调用订单服务,让后订单服务调用派单系统通知送外卖人员送单,这时候订单系统与派单系统采用MQ异步通讯. RabbitMQ解决分布式事务原理: 采用最终 ...
- SpringBoot(17)---SpringBoot整合RocketMQ
SpringBoot整合RocketMQ 上篇博客讲解了服务器集群部署RocketMQ 博客地址:RocketMQ(2)---Docker部署RocketMQ集群 这篇在上篇搭建好的基础上,将Spri ...
- 【分布式事务】使用atomikos+jta解决分布式事务问题
一.前言 分布式事务,这个问题困惑了小编很久,在3个月之前,就间断性的研究分布式事务.从MQ方面,数据库事务方面,jta方面.近期终于成功了,使用JTA解决了分布式事务问题.先写一下心得,后面的二级提 ...
- LCN解决分布式事务原理解析+项目实战(原创精华版)
写在前面: 原创不易,如果觉得不错推荐一下,谢谢! 由于工作需要,公司的微服务项目需解决分布式事务的问题,且由我进行分布式事务框架搭建和整合工作. 那么借此机会好好的将解决分布式事务的内容进行整理一下 ...
- SpringCloud+RocketMQ实现分布式事务
随着互联网公司的微服务越来越多,分布式事务已经成为了我们的经常使用的.所以我们来一步一步的实现基于RocketMQ的分布式事务.接下来,我们将要做的主题写出来. RocketMQ的分布式事务结构和说明 ...
- 使用kafka消息队列解决分布式事务(可靠消息最终一致性方案-本地消息服务)
微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务 本文转自:http://skaka.me/blog/2016/04/21/springcloud1/ 不同于单一 ...
随机推荐
- 响应式网页设计(Bootstrap)
Bootstrap官网 AOS官网 Chrome官方教程 Chrome教程 Bootstrap官网中有许多Bootstrap网站示例,大家可以参考
- Vue(27)vue-codemirror实现在线代码编译器
前言 如果我们想在Web端实现在线代码编译的效果,那么需要使用组件vue-codemirror,他是将CodeMirror进行了再次封装 支持代码高亮 62种主题颜色,例如monokai等等 支持js ...
- 小程序中使用、H5、uniapp下使用阿里巴巴iconfront图标或者新增图标
第一步:登录iconfont的账号,创建项目. 第二步:选择自己需要的图标,并添加入库(就是那个购物车的图标). 第三步:将选好的图片添加到项目.(点击上图中右上角的购物车图标). 第四步:下载资源到 ...
- 2. node接口搭建--连接MongoDB数据库 (参考https://blog.csdn.net/ncepu_Chen/article/details/98725104#_337)
1.使用mongoose连接MongoDB数据库 npm install mongoose 2.新建文件夹config存放数据库地址 3.安装MongoDB
- elementUI表单嵌套表格并对每行进行校验
elementUI表单嵌套表格并对每行进行校验 elementUI 表单嵌套表格并进行校验. 目录 效果展示 代码链接 关键代码 完整代码 效果展示 先看看这是不是需要的效果^_^ 如图,Elem ...
- Hadoop Jobhistory配置启用
Hadoop Jobhistory记录下已运行完的MapReduce作业信息并存放在指定的HDFS目录下, 默认情况下是没有启动的,需要配置完后手工启动服务. 1.修改hadoop的配置文件mapre ...
- CGO快速入门
1. 通过`improt "C"`语句开启CGO特性2. `/**/`中间是C代码,之后接 import "C" 如果存在空行 就会报错.could not d ...
- dokcer部署Redis哨兵模式
架构图 哨兵的介绍 sentinel , 中文是哨兵. 哨兵是redis 集群架构中非常重要的一个组件,主要功能如下: (1)集群监控:负责监控reidis master 和slave 进程是否正常工 ...
- pytest用例的执行顺序
Pytest执行的顺序 当pytest运行测试函数时,它会查看该测试函数中的参数,然后搜索与这些参数具有相同名称的fixture.一旦pytest找到这些对象,它就会运行这些fixture 影响执行顺 ...
- centos7.5上安装go1.13.4
一.安装 1.下载go1.13.4.linux-amd64.tar.gz 先进入官网https://golang.google.cn/ 再 https://golang.google.cn/doc/i ...