Spring Cloud Alibaba [Transfer function implementation, transfer function implementation, demonstration of distributed transaction issues not introduced, project introduction of Seata] (11)

 

Table of contents

Seata provides XA mode to realize distributed transaction_transfer function realization

Seata provides XA mode to realize distributed transaction_Transfer function is realized

Seata provides XA mode to realize distributed transaction_no demonstration of distributed transaction problem

Seata provides XA mode to realize distributed transactions_Project introduced Seata 


 

Seata provides XA mode to realize distributed transaction_transfer function realization

Realize the following functions

1. Increase the amount of Li Si's account.

Create cloud-seata-bank2

Pom introduces dependencies 

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
       </dependency>

Write the main startup class

//添加对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 *************");
   }
}

Write a YML configuration file

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

Create entity class

@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;
}

Write the persistence layer

@Component
@Mapper
public interface AccountMapper extends
BaseMapper<AccountInfo> {}

Write transfer interface

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

Write transfer interface implementation class

@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);
   }
}

Write the control layer

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

Seata provides XA mode to realize distributed transaction_Transfer function is realized

Realize the following functions

1. Decrease in Zhang San's account

2. Remotely call bank2 to transfer money to Li Si.

Create cloud-seata-bank1 

Pom introduces dependencies 

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

Write the main startup class

//添加对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 *************");
   }
}

Write a YML configuration file

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

Create entity class

@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;
}

Write the persistence layer

@Component
@Mapper
public interface AccountMapper extends BaseMapper<AccountInfo> {
}

Write transfer interface

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

Write a remote call interface

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

Write transfer interface implementation class

@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);
           }
       }
   }
}

Write the control layer

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

Seata provides XA mode to realize distributed transaction_no demonstration of distributed transaction problem

initial database data 

normal circumstances

Send request http://localhost:6001/transfer?amount=2 

 

Create anomalies 

Create an exception in the bank2 microservice

post exception test

Send request http://localhost:6001/transfer?amount=2 

Seata provides XA mode to realize distributed transactions_Project introduced Seata 

Seata implements XA key points

1. Global transactions start to use the GlobalTransactional flag.

2. Each local transaction scheme still uses the @Transactional logo.

3. Each data needs to create an undo_log table, which is the key for Seata to ensure the consistency of local transactions. 

Create UNDO_LOG table 

SEATA XA schema requires UNDO_LOG table

-- 注意此处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;

add dependencies

<dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

Modify configuration file YML

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

Bank1 microservices start global things

Note: Mark the @GlobalTransactional annotation on the Service implementation method initiated by the global transaction, and start the global transaction: GlobalTransactionalInterceptor will intercept the @GlobalTransactional annotation method to generate a global transaction ID (XID), and the XID will be passed throughout the distributed transaction. When calling remotely, spring-cloud-alibaba-seata will intercept the Feign call and pass the XID to the downstream service. 

bank2 opens things 

Test distributed things

Send request http://localhost:6001/transfer?amount=2 

 

Summarize 

Traditional 2PC (based on the database XA protocol) and Seata are two 2PC solutions for implementing 2PC. Because Seata has zero intrusion and solves the problem of traditional 2PC long-term lock resources, it is recommended to use Seata to implement 2PC.

Real-time effect feedback

1. How to enable the global thing_____ in Seata technology.

A Global logo

B GlobalTransactional logo

C Transactional logo

All of the above are wrong

2. How to enable local things____ in Seata technology.

A Global logo

B GlobalTransactional logo

C Transactional logo

All of the above are wrong

Guess you like

Origin blog.csdn.net/m0_58719994/article/details/131869732