分布式事务

目录

Seata AT事务

TC事务协调器

业务模块中添加Seata AT事务

Seata TCC事务

TCC - 两个阶段的三种操作

业务模块中添加Seata TCC事务


Seata AT事务

TC事务协调器

1.从seata官网下载事务协调器服务

2.配置:

  •    - seata/conf/registry.conf -- 连接 eureka,向注册表注册
  •    - seata/conf/file.conf -- 协调器运行期间记录的日志数据的存储位置
  •    - seata/bin/seata-server.bat -- 设置 JVM 使用的内存大小

3.在bin目录下cmd打开dos窗口,运行seata-server.bat

- 必须用JDK1.8

- 命令窗口不能关闭

- 命令窗口不能选中,否则应用会被挂起,暂停执行

业务模块中添加Seata AT事务

1.添加seata依赖

<!--seata 依赖有自动配置
    如果不添加其他 Seata配置文件,项目无法启动
-->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-alibaba-seata</artifactId>
  <version>2.0.0.RELEASE</version>
  <exclusions>
    <exclusion>
      <artifactId>seata-all</artifactId>
      <groupId>io.seata</groupId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>io.seata</groupId>
  <artifactId>seata-all</artifactId>
  <version>1.3.0</version>
</dependency>

2.三个配置:

  •    - application.yml -- 事务组的组名
spring:
  cloud:
    alibaba:
      seata:
        tx-service-group: order_tx_group # 事务组组名
  •    - registry.conf -- 设置注册中心的地址
  •    - file.conf -- 事务组对用使用哪个协调器
service {
  #transaction service group mapping
  # order_tx_group 与 yml 中的 “tx-service-group: order_tx_group” 配置一致
  # “seata-server” 与 TC 服务器的注册名一致
  # 从eureka获取seata-server的地址,再向seata-server注册自己,设置group
  vgroupMapping.order_tx_group = "seata-server"
  #only support when registry.type=file, please don't set multiple addresses
  order_tx_group.grouplist = "127.0.0.1:8091"
  #degrade, current not support
  enableDegrade = false
  #disable seata
  disableGlobalTransaction = false
}

3.自定义自动配置类,创建数据源代理对象

- AT事务的自动事务控制代码,都是由数据源代理对象提供的

package cn.tedu.order;

import com.zaxxer.hikari.HikariDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;

/*
自定义自动配置类,创建原始数据源和数据源代理对象
 */
@Configuration
public class DSConf {
    // 原始数据源
    @ConfigurationProperties(prefix = "spring.datasource")  //将配置文件中的数据库参数注入HikariDataSource对象
    @Bean
    public DataSource DataSource(){
        return new HikariDataSource();
    }
    // Seata AT事务的数据源代理对象
    @Primary  //首选对象
    @Bean
    public DataSource dataSourceProxy(DataSource ds){
        return new DataSourceProxy(ds);
    }
}

4.排除springboot默认的数据源自动配置

在启动类中添加以下注解:

//排除默认的数据源配置,应用自定义的自动配置类
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

5.业务方法上添加事务注解

   - `@Transactional` - 控制本地事务
   - `@GlobalTransactional` - 创建 TM,启动全局事务,只在第一个模块添加

Seata TCC事务

TCC 是一种有侵入的事务方案

- 所有事务控制代码都需要自己实现
- 底层的数据库、业务代码都需要修改

有些复杂情况下,AT事务无法实现自动事务控制,就需要手动控制事务的方案

TCC - 两个阶段的三种操作

- 第一个阶段

  Try - 预留资源、冻结数据

- 第二阶段

  - Confirm - 确认、提交,使用一阶段冻结的数据实现业务数据处理
  - Cancel - 取消、回滚,把一阶段冻结的数据恢复回去

业务模块中添加Seata TCC事务

1.添加seata依赖

2.三个配置文件

  •    - application.yml -- 组名
  •    - registry.conf -- eureka地址
  •    - file.conf -- 事务组对应使用的协调器

3.修改Mapper,添加新的TCC三个数据库操作

4.按照Seata TCC的规则,添加TccAction接口和实现类,实现三个操作的方法

接口

package cn.tedu.order.tcc;

import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;

import java.math.BigDecimal;

/*
在接口中要定义 TCC 三个方法
 */
@LocalTCC
public interface OrderTccAction {
    /*
    BusinessActionContext上下文对象,用来从第一阶段向第二阶段传递数据
    第一阶段需要业务数据参数用来冻结业务数据,
    为了避开seata的一个bug,最好不传递封装的对象,而是把数据打散一个个的单独传递

    第一阶段方法需要在业务代码中手动调用
     */
    @TwoPhaseBusinessAction(name = "OrderTccAction",    //指定第一阶段方法
                            commitMethod = "commit",    //指定Confirm方法
                            rollbackMethod = "rollback")//指定Cancel方法
    boolean prepare(BusinessActionContext ctx,
                    @BusinessActionContextParameter(paramName = "orderId") Long id,
                    Long userId, Long productId, Integer count, BigDecimal money);      //T - Try
    /*
    第二阶段方法由RM(资源管理器)接收TC的二阶段指令,执行二阶段方法
     */
    boolean commit(BusinessActionContext ctx);       //C - Confirm
    boolean rollback(BusinessActionContext ctx);     //C - Cancel
}

实现类

package cn.tedu.order.tcc;

import cn.tedu.order.entity.Order;
import cn.tedu.order.mapper.OrderMapper;
import io.seata.rm.tcc.api.BusinessActionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

@Component
public class OrderTccActionImpl implements OrderTccAction {
    @Autowired
    private OrderMapper orderMapper;

    @Override
    @Transactional
    public boolean prepare(BusinessActionContext ctx, Long id, Long userId, Long productId, Integer count, BigDecimal money) {
        orderMapper.createFrozen(new Order(id,userId,productId,count,money,0));
        return true;    //第一阶段冻结成功
    }

    @Override
    @Transactional
    public boolean commit(BusinessActionContext ctx) {
        //第一阶段向第二阶段传递上下文对象时,先转成json进行传递,会丢失数据的类型信息
        Long orderId = Long.valueOf(ctx.getActionContext("orderId").toString());
        orderMapper.updateStatus(orderId, 1);//订单状态改成1,正常状态
        return true;    //确认提交成功
    }

    @Override
    @Transactional
    public boolean rollback(BusinessActionContext ctx) {
        Long orderId = Long.valueOf(ctx.getActionContext("orderId").toString());
        orderMapper.deleteById(orderId);
        return true;//取消回滚成功
    }
}

5.调整业务方法,不直接完成业务,而是调用第一阶段方法冻结数据

tcc.prepare(null,order.getId(),order.getUserId(),
        order.getProductId(),order.getCount(),order.getMoney());

6.在第一个模块的业务方法上添加`@GlobalTransactional`

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值