• 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>


  • 相关阅读:
    005 Python的IDE之Pycharm的使用
    006 Python的IDE之Jupyter的使用
    004 pip的使用
    003 Python解释器源修改
    002 Python解释器安装
    BZOJ 4567 [SCOI2016]背单词 (Trie树、贪心)
    BZOJ 2085 luogu P3502 [POI2010]Hamsters (KMP、Floyd、倍增)
    UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)
    UOJ #214 [UNR #1]合唱队形 (概率期望计数、DP、Min-Max容斥)
    LOJ #2542 [PKUWC2018]随机游走 (概率期望、组合数学、子集和变换、Min-Max容斥)
  • 原文地址:https://www.cnblogs.com/muliu/p/12358737.html
Copyright © 2020-2023  润新知