目录
Seata提供XA模式实现分布式事务_转账功能实现上
Seata提供XA模式实现分布式事务_转账功能实现下
Seata提供XA模式实现分布式事务_没有引入分布式事物问题演示
Seata提供XA模式实现分布式事务_项目引入Seata
实现如下功能
1、李四账户增加金额。
创建cloud-seata-bank2
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;
}
}
实现如下功能
1、张三账户减少金额
2、远程调用bank2向李四转账。
创建cloud-seata-bank1
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;
}
}
初始数据库数据
正常情况
发送请求http://localhost:6001/transfer?amount=2
制造异常
在bank2微服务制造异常
异常后测试
发送请求http://localhost:6001/transfer?amount=2
Seata实现XA要点
1、全局事务开始使用GlobalTransactional标识。
2、每个本地事务方案仍然使用@Transactional标识。
3、每个数据都需要创建undo_log表,此表是Seata保证本地事务一致性的关键。
创建 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微服务开启全局事物
注意: 将@GlobalTransactional注解标注在全局事务发起的Service实 现方法上,开启全局事务 :GlobalTransactionalInterceptor会 拦截@GlobalTransactional注解的方法,生成全局事务ID (XID),XID会在整个分布式事务中传递。 在远程调用时,spring-cloud-alibaba-seata会拦截Feign调用将 XID传递到下游服务。
bank2开启事物
测试分布式事物
发送请求http://localhost:6001/transfer?amount=2
总结
传统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 以上都错误