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/ 不同于单一 ...
随机推荐
- Linux组
Linux组 介绍 Linux中,没有用户和文件可以脱离组而存在 用户有"组"这一属性:相关链接 文件有"所有者""组""其他组& ...
- 基于Java swing+mysql+eclipse的【图书管理系统】
本项目为Java swing项目,在工作环境中基本使用不到,但是很多学校把这个当做编程入门的项目来做,故分享出本项目供初学者参考. CSDN赞助下载:https://download.csdn.net ...
- 编写Java程序,通过给定可变参数方法,计算任意给定的多个int类型数据之和
返回本章节 返回作业目录 需求说明: 通过给定可变参数方法,计算任意给定的多个int类型数据之和. 实现思路: 定义可变形参方法,参数类型是int类型. 定义变量 sum 接受最终的和. 通过 for ...
- Java Springboot webSocket简单实现,调接口推送消息到客户端socket
Java Springboot webSocket简单实现,调接口推送消息到客户端socket 后台一般作为webSocket服务器,前台作为client.真实场景可能是后台程序在运行时(满足一定条件 ...
- MySQL启用SSL连接
1.手动创建自认证证书 1.1 创建CA证书 openssl genrsa 2048 > ca-key.pem openssl req -new -x509 -nodes -days 3600 ...
- .NET 微服务——CI/CD(3):镜像自动分发
如何通过Jenkins完成镜像分发?基本做法是:打包镜像→上传镜像到仓库→脚本分发.镜像仓库也有很多,比如docker hub.Harbor等,今天这一篇讲一下基于阿里云镜像仓库的操作. 首先,准备一 ...
- koa路由接口
const router = require('koa-router')() //返回一个页面 router.get('/', async (ctx, next) => { global.con ...
- Jsp页面中常见的page指令
注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6513327323628962312/ 1.<JSP页面实际上就是Servlet> 2.<JSP页 ...
- 【PTA】6-1 计算两个复数之积 (10 分)
本题要求实现一个计算复数之积的简单函数. 函数接口定义: struct complex multiply(struct complex x, struct complex y); 其中struct c ...
- MATLAB中插值算法实现
%%%1.M文件%(1).以往少的程序可以在命令行窗口进行编码,但大量的程序编排到命令行窗口,%会有造成乱码的危险.(2).如果将命令编成程序存储在一个文件中(M文件),依次运行文件中的命令,则可以重 ...