当前位置:   article > 正文

在Spring Boot中实现分布式事务管理_springboot两个服务怎么做事务

springboot两个服务怎么做事务

在Spring Boot中实现分布式事务管理

大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!

在微服务架构中,服务通常分布在不同的节点上,每个服务都有自己的数据库。由于业务逻辑的复杂性,可能需要在多个服务之间进行事务处理,这就引入了分布式事务的概念。本文将介绍如何在Spring Boot中实现分布式事务管理,确保数据的一致性和完整性。

分布式事务的挑战

在分布式系统中,事务的管理比单体应用复杂得多。主要挑战包括:

  1. 网络不可靠:网络延迟和分区可能导致事务无法及时提交或回滚。
  2. 服务独立性:每个服务独立部署和运行,事务的管理需要跨多个服务。
  3. 数据一致性:确保所有参与事务的数据库保持一致状态。

常用的分布式事务解决方案

  1. 两阶段提交(2PC):经典的分布式事务协议,但性能和可靠性有限。
  2. 本地消息表:通过消息队列实现事务的最终一致性。
  3. TCC(Try-Confirm-Cancel):灵活但实现复杂。
  4. Saga模式:长事务拆分为一系列有序的子事务,通过补偿机制保证一致性。

本文将以Saga模式为例,介绍如何在Spring Boot中实现分布式事务管理。

环境准备

  1. Spring Boot:2.x版本
  2. 数据库:MySQL
  3. 消息队列:RabbitMQ

实现步骤

  1. 引入依赖
  2. 配置数据库和消息队列
  3. 编写业务逻辑
  4. 实现Saga事务管理

引入依赖

pom.xml文件中添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

配置数据库和消息队列

application.properties中配置数据库和RabbitMQ:

spring.datasource.url=jdbc:mysql://localhost:3306/saga_db
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

编写业务逻辑

我们假设有两个服务:订单服务和库存服务。订单服务在创建订单时需要调用库存服务来扣减库存。

订单实体和仓库实体:

package cn.juwatech.order.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String productCode;
    private Integer quantity;
    private String status;

    // Getters and Setters
}

package cn.juwatech.inventory.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Inventory {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String productCode;
    private Integer availableQuantity;

    // Getters and Setters
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

订单服务和库存服务的Repository接口:

package cn.juwatech.order.repository;

import cn.juwatech.order.entity.Order;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderRepository extends JpaRepository<Order, Long> {
}

package cn.juwatech.inventory.repository;

import cn.juwatech.inventory.entity.Inventory;
import org.springframework.data.jpa.repository.JpaRepository;

public interface InventoryRepository extends JpaRepository<Inventory, Long> {
    Inventory findByProductCode(String productCode);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

实现Saga事务管理

  1. 订单服务
package cn.juwatech.order.service;

import cn.juwatech.order.entity.Order;
import cn.juwatech.order.repository.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private InventoryService inventoryService;

    @Transactional
    public void createOrder(Order order) {
        order.setStatus("PENDING");
        orderRepository.save(order);
        inventoryService.reserveInventory(order.getProductCode(), order.getQuantity());
        order.setStatus("COMPLETED");
        orderRepository.save(order);
    }

    public void cancelOrder(Order order) {
        order.setStatus("CANCELLED");
        orderRepository.save(order);
        inventoryService.releaseInventory(order.getProductCode(), order.getQuantity());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  1. 库存服务
package cn.juwatech.inventory.service;

import cn.juwatech.inventory.entity.Inventory;
import cn.juwatech.inventory.repository.InventoryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class InventoryService {

    @Autowired
    private InventoryRepository inventoryRepository;

    public void reserveInventory(String productCode, int quantity) {
        Inventory inventory = inventoryRepository.findByProductCode(productCode);
        if (inventory.getAvailableQuantity() < quantity) {
            throw new RuntimeException("Insufficient inventory");
        }
        inventory.setAvailableQuantity(inventory.getAvailableQuantity() - quantity);
        inventoryRepository.save(inventory);
    }

    public void releaseInventory(String productCode, int quantity) {
        Inventory inventory = inventoryRepository.findByProductCode(productCode);
        inventory.setAvailableQuantity(inventory.getAvailableQuantity() + quantity);
        inventoryRepository.save(inventory);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  1. 消息监听器
package cn.juwatech.order.listener;

import cn.juwatech.order.entity.Order;
import cn.juwatech.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class OrderListener {

    @Autowired
    private OrderService orderService;

    @RabbitListener(queues = "order.queue")
    public void onOrderEvent(Order order) {
        try {
            orderService.createOrder(order);
        } catch (Exception e) {
            orderService.cancelOrder(order);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

配置消息队列

application.properties中添加以下配置:

spring.rabbitmq.template.default-receive-queue=order.queue
  • 1

总结

本文详细介绍了如何在Spring Boot中实现分布式事务管理。我们通过Saga模式,将订单服务和库存服务的事务操作结合起来,确保在分布式系统中实现数据的一致性和完整性。通过消息队列和事务管理,我们构建了一个可靠的分布式事务管理系统。

本文著作权归聚娃科技微赚淘客系统开发者团队,转载请注明出处!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/995415
推荐阅读
相关标签
  

闽ICP备14008679号