1 引出分布式事务问题

1.1 seata-service-account编写查询用户、远程调用下订单接口

@RestController

@RequestMapping("/accountTbl")

public class AccountTblController {

@Autowired

AccountTblMapper accountTblMapper;

@Autowired

OrderFeign orderFeign;

@GetMapping("/insertOrder")

public Object insertOrder() {

// 查询用户

AccountTbl accountTbl = accountTblMapper.selectById("11111111");

// 下单

Object order = orderFeign.insertOrder(accountTbl.getUserId(), "iphone11", 1, 1);

// 修改余额

accountTbl.setMoney(accountTbl.getMoney() - 1);

accountTblMapper.updateById(accountTbl);

return order;

}

}

@FeignClient(name = "seata-service-order")

public interface OrderFeign {

@GetMapping("orderTbl/insertOrder")

Object insertOrder(@RequestParam String userId,@RequestParam String commodityCode,@RequestParam int count,@RequestParam int money);

}

1.2 seata-service-order编写下订单,远程调用减库存接口

@RestController

@RequestMapping("/orderTbl")

public class OrderTblController {

@Autowired

OrderTblMapper orderTblMapper;

@Autowired

StorageFeign storageFeign;

@GetMapping("insertOrder")

public Object insertOrder(String userId, String commodityCode, int count, int money) {

// 下定单

OrderTbl orderTbl = new OrderTbl();

orderTbl.setUserId(userId);

orderTbl.setCommodityCode(commodityCode);

orderTbl.setCount(count);

orderTbl.setMoney(1);

// 下订单扣库存

orderTblMapper.insert(orderTbl);

Object storage = storageFeign.updateStorage(commodityCode, count);

return orderTbl;

}

}

@FeignClient(name = "seata-service-storage")

public interface StorageFeign {

@GetMapping("/storageTbl/updateStorage")

Object updateStorage(@RequestParam String commodityCode,@RequestParam int count);

}

1.3 seata-service-storage编写减库存接口

@RestController

@RequestMapping("/storageTbl")

public class StorageTblController {

@Autowired

StorageTblMapper storageTblMapper;

@GetMapping("updateStorage")

Object updateStorage(String commodityCode, int count){

// 查询库存

StorageTbl storageTbl = storageTblMapper.selectOne(new LambdaQueryWrapper().eq(StorageTbl::getCommodityCode, commodityCode));

// 减去库存更新

storageTbl.setCount(storageTbl.getCount()-count);

int i = storageTblMapper.updateById(storageTbl);

return storageTbl;

}

}

1.4 引出分布式事务

当我们关闭seata-service-storage服务,访问/accountTbl/insertOrder接口,会发现下单成功了,但是未扣库存,所以需要引入分布式事务,对一些跨服务的改库操作进行全局管理

2 集成Seata解决分布式事务问题

2.1 各个数据据添加undo_log表

CREATE TABLE `undo_log` (

`id` bigint NOT NULL AUTO_INCREMENT,

`branch_id` bigint NOT NULL,

`xid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,

`context` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,

`rollback_info` longblob NOT NULL,

`log_status` int NOT NULL,

`log_created` datetime NOT NULL,

`log_modified` datetime NOT NULL,

PRIMARY KEY (`id`) USING BTREE,

UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) USING BTREE

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

2.2 父pom添加seata依赖

io.seata

seata-spring-boot-starter

1.6.1

com.alibaba

druid

com.alibaba.cloud

spring-cloud-starter-alibaba-seata

io.seata

seata-spring-boot-starter

2.3 各模块添加yml配置

seata:

enabled: true

application-id: seata-service-account # 添加为服务名

tx-service-group: my_test_tx_group

config:

type: nacos

nacos:

namespace:

serverAddr: 127.0.0.1:8848

group: SEATA_GROUP

registry:

type: nacos

nacos:

application: seata-server

server-addr: 127.0.0.1:8848

group: SEATA_GROUP

namespace:

2.4 调用链开端AccountTblController接口添加@GlobalTransactional注解

2.5 手动实现xid传递

手动实现xid传递,实际cloud alibaba通过已实现了自动传递,但是新版openfeign移除了很多组件,需要自己实现,添加配置类,并重新去掉自动配置

/**

* @author wuKeFan

* @date 2020/11/27

*/

@Component

@ConditionalOnClass({RequestInterceptor.class, GlobalTransactional.class})

public class SeataRequestInterceptor implements RequestInterceptor {

@Override

public void apply(RequestTemplate template) {

String currentXid = RootContext.getXID();

if (StrUtil.isNotBlank(currentXid) && !template.url().startsWith(Auth.CHECK_TOKEN_URI) && !template.url().startsWith(Auth.CHECK_RBAC_URI)) {

template.header(RootContext.KEY_XID, currentXid);

}

}

}

@Configuration

public class WebMvcConfig implements WebMvcConfigurer {

@Override

public void addInterceptors(InterceptorRegistry registry) {

registry.addInterceptor(new SeataHandlerInterceptor()).addPathPatterns("/**");

}

}

@SpringBootApplication(exclude = {SeataFeignClientAutoConfiguration.class})

2.6 启动各个项目,访问接口,全局事务提交成功

2.7 模拟异常

当账户因为异常回滚后,并没有订单及库存数据不一致,全局事务回滚

好文链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: