Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)

 

目录

Seata提供XA模式实现分布式事务_转账功能实现上

Seata提供XA模式实现分布式事务_转账功能实现下

Seata提供XA模式实现分布式事务_没有引入分布式事物问题演示

Seata提供XA模式实现分布式事务_项目引入Seata 


 

Seata提供XA模式实现分布式事务_转账功能实现上

实现如下功能

1、李四账户增加金额。

创建cloud-seata-bank2

Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)_第1张图片

pom引入依赖 

        
            org.springframework.boot
            spring-boot-starter-web
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.5.1
        
        
            mysql
            mysql-connector-java
            5.1.49
        
        
            org.projectlombok
            lombok
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
       

编写主启动类

//添加对mapper包扫描 Mybatis-plus
@MapperScan("com.tong.mapper")
//开启OpenFiegn
@EnableFeignClients
@SpringBootApplication
@Slf4j
//开启发现注册
@EnableDiscoveryClient
public class SeataBank2Main6002 {
    public static void main(String[] args) {
        SpringApplication.run(SeataBank1Main6002.class,args);
        log.info("**************SeataBank1Main6002 *************");
   }
}

编写YML配置文件

server:
 port: 6002
spring:
 application:
   name: seata-bank2
 cloud:
   nacos:
     discovery:
        # Nacos server地址
       server-addr: 192.168.66.101:8848
 datasource:
   url: jdbc:mysql://localhost:3306/bank2?
useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
   username: root
   password: 123456
   driver-class-name: com.mysql.jdbc.Driver

创建实体类

@AllArgsConstructor
@NoArgsConstructor
@Builder
@TableName("account_info")
@Data
public class AccountInfo {
    //id
    @TableId
    private Long id;
    //户主姓名
    @TableField("account_name")
    private String accountName;
    //银行卡号
    @TableField("account_no")
    private String accountNo;
    //账户密码
    @TableField("account_password")
    private String accountPassword;
    //账户余额
    @TableField("account_balance")
    private Double accountBalance;
}

编写持久层

@Component
@Mapper
public interface AccountMapper extends
BaseMapper {}

编写转账接口

public interface IAccountInfoService {
    //李四增加金额
    void updateAccountBalance(String accountNo, Double amount);
}

编写转账接口实现类

@Service
@Slf4j
public class AccountInfoServiceImpl implements IAccountInfoService {
    @Autowired
    AccountMapper accountMapper;
    @Override
    public void updateAccountBalance(String accountNo, Double amount) {
        // 1. 获取用户信息
        AccountInfo accountInfo = accountMapper.selectById(accountNo);
        accountInfo.setAccountBalance(accountInfo.getAccountBalance() + amount);
        accountMapper.updateById(accountInfo);
   }
}

编写控制层

@RestController
@RequestMapping("/bank2")
public class Bank2Controller {
    @Autowired
    IAccountInfoService accountInfoService;
    //接收张三的转账
    @GetMapping("/transfer")
    public String transfer(Double amount){
        //李四增加金额
        accountInfoService.updateAccountBalance("3",amount);
        return "bank2"+amount;
   }
}

Seata提供XA模式实现分布式事务_转账功能实现下

实现如下功能

1、张三账户减少金额

2、远程调用bank2向李四转账。

创建cloud-seata-bank1 

Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)_第2张图片

pom引入依赖 

        
            org.springframework.boot
            spring-boot-starter-web
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.5.1
        
        
            mysql
            mysql-connector-java
            5.1.49
        
        
            org.projectlombok
            lombok
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
        
            org.springframework.cloud
            spring-cloud-starter-loadbalancer
        

编写主启动类

//添加对mapper包扫描 Mybatis-plus
@MapperScan("com.tong.mapper")
//开启OpenFiegn
@EnableFeignClients
@SpringBootApplication
@Slf4j
//开启发现注册
@EnableDiscoveryClient
public class SeataBank1Main6001 {
    public static void main(String[] args) {
        SpringApplication.run(SeataBank1Main6001.class,args);
        log.info("**************SeataBank1Main6001 *************");
   }
}

编写YML配置文件

server:
 port: 6001
spring:
 application:
   name: seata-bank1
 cloud:
   nacos:
     discovery:
        # Nacos server地址
       server-addr: 192.168.66.101:8848
 datasource:
   url: jdbc:mysql://localhost:3306/bank1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
   username: root
   password: 123456
   driver-class-name: com.mysql.jdbc.Driver

创建实体类

@AllArgsConstructor
@NoArgsConstructor
@Builder
@TableName("account_info")
@Data
public class AccountInfo {
    //id
    @TableId
    private Long id;
    //户主姓名
    @TableField("account_name")
    private String accountName;
    //银行卡号
    @TableField("account_no")
    private String accountNo;
    //账户密码
    @TableField("account_password")
    private String accountPassword;
    //账户余额
    @TableField("account_balance")
    private Double accountBalance;
}

编写持久层

@Component
@Mapper
public interface AccountMapper extends BaseMapper {
}

编写转账接口

public interface IAccountInfoService {
    //张三扣减金额
    public void updateAccountBalance(String accountNo, Double amount);
}

编写远程调用接口

@Component
@FeignClient(value="seata-bank2")
public interface Bank2Client {
    //远程调用李四的微服务
    @GetMapping("/bank2/transfer")
    String transfer(@RequestParam("amount") Double amount);
}

编写转账接口实现类

@Service
@Slf4j
public class AccountInfoServiceImpl implements IAccountInfoService {
    @Autowired
    AccountMapper accountMapper;
    @Autowired
    Bank2Client bank2Client;
    @Override
    public void updateAccountBalance(String accountNo, Double amount) {
        // 1. 获取用户信息
        AccountInfo accountInfo = accountMapper.selectById(2);
        // 2. 判断张三账户余额是否有钱
        if (accountInfo.getAccountBalance() > amount){
            //扣减张三的金额
           accountInfo.setAccountBalance(accountInfo.getAccountBalance()-amount);
            int result = accountMapper.updateById(accountInfo);
            if (result!=0){
                //调用李四微服务,转账
                bank2Client.transfer(amount);
           }
       }
   }
}

编写控制层

@RestController
public class Bank1Controller {
    @Autowired
    IAccountInfoService IAccountInfoService;
    //张三转账
    @GetMapping("/transfer")
    public String transfer(Double amount){
        IAccountInfoService.updateAccountBalance("1",amount);
        return "bank1"+amount;
   }
}

Seata提供XA模式实现分布式事务_没有引入分布式事物问题演示

初始数据库数据 

Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)_第3张图片

正常情况

发送请求http://localhost:6001/transfer?amount=2 

Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)_第4张图片 

制造异常 

在bank2微服务制造异常

Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)_第5张图片

异常后测试

发送请求http://localhost:6001/transfer?amount=2 

Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)_第6张图片

Seata提供XA模式实现分布式事务_项目引入Seata 

Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)_第7张图片

Seata实现XA要点

1、全局事务开始使用GlobalTransactional标识。

2、每个本地事务方案仍然使用@Transactional标识。

3、每个数据都需要创建undo_log表,此表是Seata保证本地事务一致性的关键。 

Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)_第8张图片

创建 UNDO_LOG 表 

SEATA XA 模式需要 UNDO_LOG 表

-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
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;

添加依赖


     com.alibaba.cloud
     spring-cloud-starter-alibaba-seata

修改配置文件YML

seata:
  # 注册中心
 registry:
   type: file
 service:
    # seata服务端的地址和端口信息,多个使用英文分号分隔
   grouplist:
     default: 192.168.66.100:9999
 tx-service-group: my_test_tx_group

bank1微服务开启全局事物

Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)_第9张图片

注意: 将@GlobalTransactional注解标注在全局事务发起的Service实 现方法上,开启全局事务 :GlobalTransactionalInterceptor会 拦截@GlobalTransactional注解的方法,生成全局事务ID (XID),XID会在整个分布式事务中传递。 在远程调用时,spring-cloud-alibaba-seata会拦截Feign调用将 XID传递到下游服务。 

bank2开启事物 

Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)_第10张图片

测试分布式事物

发送请求http://localhost:6001/transfer?amount=2 

Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)_第11张图片 

总结 

传统2PC(基于数据库XA协议)和Seata实现2PC的两种2PC方案, 由于Seata的零入侵并且解决了传统2PC长期锁资源的问题,所以推荐采用Seata实现2PC。

实时效果反馈

1.Seata技术中如何开启全局事物_____。

A Global标识

B GlobalTransactional标识

C Transactional标识

D 以上都错误

2.Seata技术中如何开启本地事物____。

A Global标识

B GlobalTransactional标识

C Transactional标识

D 以上都错误

你可能感兴趣的:(Spring全家桶,Spring,Cloud,java,sentinel)