使用Spring Boot實現分散式事務
大家好,我是微賺淘客系統3.0的小編,是個冬天不穿秋褲,天冷也要風度的程式猿!
在微服務架構中,分散式事務是一個重要的概念,它用於確保在分散式系統中各個服務之間的資料一致性。分散式事務的實現相對複雜,因為它需要跨越多個服務、資料庫或訊息佇列來維護資料的一致性。本文將詳細介紹如何使用Spring Boot實現分散式事務,重點介紹如何使用Spring Cloud和Seata框架來管理分散式事務。
一、分散式事務的基本概念
分散式事務是指在多個不同的資料庫或服務之間執行的事務操作,這些操作需要保證一致性和完整性。分散式事務通常透過兩階段提交(2PC)、三階段提交(3PC)或TCC(Try-Confirm/Cancel)等協議來實現。
二、Seata簡介
Seata(Simple Extensible Autonomous Transaction Architecture)是阿里巴巴開源的一款分散式事務解決方案,提供了高效且易用的分散式事務服務。Seata支援AT、TCC、SAGA和XA等多種事務模式。
三、環境準備
- JDK 8或以上版本
- Maven 3或以上版本
- MySQL資料庫
- Seata Server
四、建立Spring Boot專案
首先,我們使用Spring Initializr建立一個新的Spring Boot專案,並新增必要的依賴。
- 開啟 Spring Initializr
- 輸入專案資訊:
- Group:
cn.juwatech
- Artifact:
spring-boot-seata
- Group:
- 新增依賴:
- Spring Web
- Spring Data JPA
- MySQL Driver
- Seata Spring Boot Starter
點選“Generate”按鈕生成專案並下載,然後解壓專案檔案。
五、配置Seata
- 在
src/main/resources
目錄下建立application.yml
配置檔案,新增以下內容:
server:
port: 8080
spring:
application:
name: spring-boot-seata
datasource:
url: jdbc:mysql://localhost:3306/seata_example
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
seata:
enabled: true
application-id: spring-boot-seata
tx-service-group: my_test_tx_group
- 在
src/main/resources
目錄下建立seata.conf
配置檔案,新增以下內容:
transport {
type = "TCP"
server = "NIO"
heartbeat = "true"
serialization = "seata"
compressor = "none"
}
service {
vgroupMapping.my_test_tx_group = "default"
enableDegrade = false
disableGlobalTransaction = false
}
client {
rm {
asyncCommitBufferLimit = 10000
lock {
retryTimes = 30
retryInterval = 10
}
reportRetryCount = 5
tableMetaCheckEnable = false
}
tm {
commitRetryCount = 5
rollbackRetryCount = 5
}
undo {
dataValidation = true
logSerialization = "jackson"
onlyCareUpdateColumns = true
}
}
support {
spring {
datasource-autoproxy = false
}
}
六、編寫業務邏輯
- 建立實體類
Order
和Account
:
package cn.juwatech.seata.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 userId;
private String productId;
private Integer count;
private Double money;
// getters and setters
}
package cn.juwatech.seata.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String userId;
private Double balance;
// getters and setters
}
- 建立
OrderRepository
和AccountRepository
:
package cn.juwatech.seata.repository;
import cn.juwatech.seata.entity.Order;
import org.springframework.data.jpa.repository.JpaRepository;
public interface OrderRepository extends JpaRepository<Order, Long> {
}
package cn.juwatech.seata.repository;
import cn.juwatech.seata.entity.Account;
import org.springframework.data.jpa.repository.JpaRepository;
public interface AccountRepository extends JpaRepository<Account, Long> {
Account findByUserId(String userId);
}
- 建立服務類
OrderService
和AccountService
:
package cn.juwatech.seata.service;
import cn.juwatech.seata.entity.Order;
import cn.juwatech.seata.repository.OrderRepository;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@GlobalTransactional(name = "my_test_tx_group", rollbackFor = Exception.class)
public void createOrder(Order order) {
orderRepository.save(order);
}
}
package cn.juwatech.seata.service;
import cn.juwatech.seata.entity.Account;
import cn.juwatech.seata.repository.AccountRepository;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class AccountService {
@Autowired
private AccountRepository accountRepository;
@GlobalTransactional(name = "my_test_tx_group", rollbackFor = Exception.class)
public void decreaseBalance(String userId, double amount) {
Account account = accountRepository.findByUserId(userId);
if (account != null && account.getBalance() >= amount) {
account.setBalance(account.getBalance() - amount);
accountRepository.save(account);
} else {
throw new RuntimeException("Insufficient balance");
}
}
}
- 建立控制器
OrderController
:
package cn.juwatech.seata.controller;
import cn.juwatech.seata.entity.Order;
import cn.juwatech.seata.service.AccountService;
import cn.juwatech.seata.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/orders")
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private AccountService accountService;
@PostMapping("/create")
public String createOrder(@RequestBody Order order) {
orderService.createOrder(order);
accountService.decreaseBalance(order.getUserId(), order.getMoney());
return "Order created successfully";
}
}
七、執行並驗證
啟動 Spring Boot 應用程式,並驗證分散式事務功能。
- 執行
SpringBootSeataApplication
類,啟動 Spring Boot 應用程式。 - 使用 Postman 或其他工具傳送 POST 請求到
http://localhost:8080/orders/create
,請求體為:
{
"userId": "1",
"productId": "P1001",
"count": 2,
"money": 200.00
}
- 檢查 MySQL 資料庫,驗證訂單和賬戶資訊是否正確更新。
透過以上步驟,我們成功地將 Spring Boot 應用與 Seata 整合,實現了分散式事務管理。Seata 提供了強大的分散式事務管理功能,使得在微服務架構中實現資料一致性變得更加容易和高效。
著作權歸聚娃科技微賺淘客系統開發者團隊,轉載請註明出處!