Spring Cloud Alibaba 06_使用 Seata 实现分布式事务

x33g5p2x  于2021-12-18 转载在 其他  
字(5.6k)|赞(0)|评价(0)|浏览(469)

Spring Cloud Alibaba 06_使用 Seata实现分布式事务

创建 order 模块,选择:spring webJDBC APIMySQL Driver

创建 pay 模块,选择:spring webJDBC APIMySQL Driver

修改 order 和 pay 的父工程:

<parent>
    <groupId>com.blu</groupId>
    <artifactId>springcloudalibabademo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</parent>

创建数据库 order,创建表 orders,字段 idusername

创建数据库 pay,创建表 pay,字段 idusername

order 模块的 application.yml 配置文件:

server:
  port: 8090

spring:
  application:
    name: order
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/order
    username: root
    password: 123456

pay 模块的 application.yml 配置文件

server:
  port: 8100

spring:
  application:
    name: pay
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/pay
    username: root
    password: 123456

OrderService:

package com.blu.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void save(){
        this.jdbcTemplate.update("insert into orders(username) value ('张三')");
    }

}

PayService:

package com.blu.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class PayService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void save(){
        this.jdbcTemplate.update("insert into pay(username) value ('张三')");
    }
}

OrderApplication:注册 RestTemplate

package com.blu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}

OrderController:

package com.blu.controller;

import com.blu.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class OrderController {

    @Autowired
    private OrderService orderService;

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("save")
    public String save(){
        //创建订单
        this.orderService.save();
        int i = 1/0;
        //支付
        this.restTemplate.getForObject("http://localhost:8100/save",String.class);
        return "success";
    }

}

PayController:

package com.blu.controller;

import com.blu.service.PayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PayController {

    @Autowired
    private PayService payService;

    @GetMapping("save")
    public String save(){
        this.payService.save();
        return "success";
    }

}

启动访问:http://localhost:8090/save 出现报错

检查数据库,发现 orders 表成功插入数据,但 pay 表没有,这就是 分布式异常

使用 Seata 实现分布式事务

seata-server 下载地址:https://github.com/seata/seata/releases

解压后,修改 registry.conf:

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"

  nacos {
    serverAddr = "localhost"
    namespace = ""
    cluster = "default"
  }

}

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "localhost"
    namespace = ""
  }

}

修改 nacos-config.txt:

  • 删除行:
service.vgroup_mapping.my_test_tx_group=default
  • 添加行:
service.vgroup_mapping.order=default
service.vgroup_mapping.pay=default
  • 启动 nacos,然后在 seataconf 目录下,执行 nacos-config.sh ,让 seata 的配置写入 nacos 服务中

注:Windows系统无法直接执行.sh文件,需要使用git bash执行

sh nacos-config.sh 127.0.0.1

  • 启动 Seata Servercmd 进入 seatabin 目录,然后使用以下命令启动:

注:JDK 8 以上的环境无法启动 Seata Server

seata-server.bat -p 8020 -m file
  • 如果在 nacos 的服务列表中出现了 serverAddr 服务,则说明 Seata Server 已经成功启动了

  • seataconf 目录下有一个 db_undo_log.sql 文件,打开它,里面有一段创建 undo_log 表的SQL语句:
CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

分别在 orderpay 数据库中执行以上sql来创建 undo_log 表(用于记录需要回滚的信息)

  • orderpay 两个模块中都添加 SeataNacos Config 组件:
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
	<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
	<version>2.2.1.RELEASE</version>
</dependency>
  • orderpay 两个模块的 JDBCTemplate 添加代理数据源:

注意这里的 DataSourceProxy 的包是 io.seata.rm.datasource.DataSourceProxy
DataSource 的包是 javax.sql.DataSource

@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
	return new JdbcTemplate(new DataSourceProxy(dataSource));
}
  • 将之前修改好的 registry.conf 复制到 orderpay 两个模块的 resources 目录下
  • 分别在 orderpay 两个模块中创建 bootstrap.yml 配置文件:
spring:
  application:
    name: order
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        namespace: public
        group: SEATA_GROUP
    alibaba:
      seata:
        tx-service-group: ${spring.application.name}
spring:
  application:
    name: pay
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        namespace: public
        group: SEATA_GROUP
    alibaba:
      seata:
        tx-service-group: ${spring.application.name}

至此,Seata 的环境就搭建完成了!

  • 在 OrderController 的 save() 方法上添加 @GlobalTransactional 注解
  • 然后重新启动,访问:http://localhost:8090/save 报错
  • 检查数据库,结果发现 orders 和 pay 表都没有添加数据

相关文章