添加undo_log表
Seata的AT模式下之所以在第一阶段直接提交事务,依赖的是需要在每个RM创建一张undo_log表,记录业务执行前后的数据快照。
如果二阶段需要回滚,直接根据undo_log表回滚,如果执行成功,则在第二阶段删除对应的快照数据。
分别在项目的 seata-account、seata-order、seata-storage 的三个数据库(两个也行)执行脚本创建 undo_log 表
配置文件:
# 分布式事务配置
seata:
#设置事务实现模式
data-source-proxy-mode: AT
tx-service-group: my_seata_group # 安装时config.txt文件中事务组分组的名称!!
enable-auto-data-source-proxy: true
registry:
type: nacos
nacos:
server-addr: 服务器ip:8848
namespace: seata_namespace_id # 对应registry.conf里的namespace值
group: SEATA_GROUP # 对应registry.conf里的group值
config:
type: nacos
nacos:
server-addr: 服务器ip:8848
namespace: seata_namespace_id # 对应registry.conf里的namespace值
group: SEATA_GROUP # 对应registry.conf里的group值
config.txt文件:
用到seata工程的代码都需要引入上面👆配置文件内容
// 库存工程
@MapperScan("com.for.stock.mapper")
@SpringBootApplication
public class StockApplication {
public static void main(String[] args) {
SpringApplication.run(StockApplication.class, args);
}
}
@Slf4j
@Service
public class StockServiceImpl implements StockService {
@Autowired
StockMapper stockMapper;
/**
* 子分支RM
* 扣减库存
*/
@Transactional
public void deductStock() {
stockMapper.deductStock();
if (1 == 1) {
// log.info("模拟业务出错", 1 / 0);
}
}
/**其余代码与平常一致*/
<update id="deductStock">
update stock_t set stock = stock-1 WHERE id = 1 and stock >0;
</update>
// openfeign工程
package com.for.api.service;
@FeignClient(name = "seata-stock" , path="/stock")
public interface StockFeignService {
@PostMapping("/deductStock")
void deductStock();
}
// 订单工程
@MapperScan("com.for.order.mapper")
@EnableFeignClients(value = "com.for.api.service" )
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
@Slf4j
@Service
public class TOrderServiceImpl implements TOrderService {
@Resource
TOrderMapper orderMapper;
@Autowired
StockFeignService stockFeignService;
/**
* 主分⽀TM
*/
@GlobalTransactional
public void shopping(TOrder order) {
log.info("开启第⼀个事务");
createOrder(order);
log.info("开启第⼆个事务");
stockFeignService.deductStock();
}
/**
* ⼦分⽀RM
* 创建订单
*/
@Transactional
public boolean createOrder(TOrder order) {
order.setOrderNo(UUID.randomUUID().toString());
orderMapper.insert(order);
//模拟出错
if (order.getUserId() == 1) {
// log.info("模拟业务出错", 1 / 0);
}
return true;
}
}
可设置断点查看各表的情况,包括undo_log与seata库的global_table等表的情况