微服务多模块feign更新数据问题
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
文章目录
最近在做一个财务系统用到了两个模块bill账单模块和data数据模块bill模块的数据是来自data模块的。
正确的流程是bill模块更新数据状态再用feign调用data模块更新数据状态
代码正常执行肯定是没问题的但是测试的时候代码出问题了抛出了异常然后就发现一个模块数据更新到数据库了另一个模块数据回滚了造成了数据不一致问题。
修改了代码进行测试
问题测试
1.bill模块抛异常data模块正常
bill模块代码
@Transactional
public CommonResult verification(BillConfirmRequest request) {
//更新账单表
int update = billMapper.update(null, new LambdaUpdateWrapper<BillDO>()
.set(BillDO::getState, 9).eq(BillDO::getId, request.getId()));
//更新业务表
if (update > 0) {
//bill模块feign调用data模块
businessBillControllerFeign.verificationBillRpc(request);
throw new RuntimeException("testtttttttttttttt");
}
return CommonResult.error(VERIFICATION_FAIL);
}
data模块代码
@Transactional
public CommonResult verificationBillRpc(BillConfirmRequest request) {
//更新业务表
businessBillMapper.update(null,
new LambdaUpdateWrapper<BusinessBillDO>()
.set(BusinessBillDO::getState, 9)
.eq(BusinessBillDO::getBillId, request.getId()));
//其他业务处理
Collection<BusinessBillCommand> values = applicationContext
.getBeansOfType(BusinessBillCommand.class).values();
for (BusinessBillCommand serviceImpl : values) {
serviceImpl.verificationBill(request.getId(), request.getOwnerCode());
}
return CommonResult.ok("核销账单成功");
}
结果bill数据回滚data数据更新到数据库
2.bill模块抛异常data模块正常
bill模块代码
@Transactional
public CommonResult verification(BillConfirmRequest request) {
//更新账单表
int update = billMapper.update(null, new LambdaUpdateWrapper<BillDO>()
.set(BillDO::getState, 9).eq(BillDO::getId, request.getId()));
//更新业务表
if (update > 0) {
//bill模块feign调用data模块
return businessBillControllerFeign.verificationBillRpc(request);
}
return CommonResult.error(VERIFICATION_FAIL);
}
data模块代码
@Transactional
public CommonResult verificationBillRpc(BillConfirmRequest request) {
//更新业务表
int update = businessBillMapper.update(null,
new LambdaUpdateWrapper<BusinessBillDO>()
.set(BusinessBillDO::getState, 9)
.eq(BusinessBillDO::getBillId, request.getId()));
if (update>0){
throw new RuntimeException("testtttttttttttttt");
}
//其他业务处理
Collection<BusinessBillCommand> values = applicationContext
.getBeansOfType(BusinessBillCommand.class).values();
for (BusinessBillCommand serviceImpl : values) {
serviceImpl.verificationBill(request.getId(), request.getOwnerCode());
}
return CommonResult.ok("核销账单成功");
}
结果bill更新到数据库data数据回滚
网上查资料得到原因
微服务中某事务内通过feign调用多个api但Transcational注解的事务只对本服务的流程有效feign调用的接口不会回滚。
解决方案
1.分布式事务
首先想到的就是分布式事务但是这个系统不是很复杂使用分布式事务大大增加了系统的复杂性在这个系统不适用大系统首选。
2.复制data的dao mapper到bill中
就是讲data模块的model dao mapper复制到bill模块中这样bill也能直接操作这几张表了就不用feign调用data再操作表了但是model dao mapper各有10个多要是都复制过去显得很冗余很丑陋了
3.判断feign返回值抛异常做回滚
bill模块代码
@Transactional
public CommonResult verification(BillConfirmRequest request) {
//更新账单表
int update = billMapper.update(null, new LambdaUpdateWrapper<BillDO>()
.set(BillDO::getState, 9).eq(BillDO::getId, request.getId()));
//更新业务表
if (update > 0) {
CommonResult commonResult = businessBillControllerFeign.verificationBillRpc(request);
//这里判断feign的返回值10001是全局异常的code
if(commonResult.getCode()==10001){
throw new RuntimeException("回滚");
}
}
return CommonResult.error(VERIFICATION_FAIL);
}
data模块代码
@Transactional
public CommonResult verificationBillRpc(BillConfirmRequest request) {
//更新业务表
int update = businessBillMapper.update(null, new LambdaUpdateWrapper<BusinessBillDO>()
.set(BusinessBillDO::getState, 9).eq(BusinessBillDO::getBillId, request.getId()));
if (update > 0) {
throw new RuntimeException("testtttttttttttttt");
}
//其他业务处理
Collection<BusinessBillCommand> values = applicationContext
.getBeansOfType(BusinessBillCommand.class).values();
for (BusinessBillCommand serviceImpl : values) {
serviceImpl.verificationBill(request.getId(), request.getOwnerCode());
}
return CommonResult.ok("核销账单成功");
}
bill会判断feign的返回值如果data模块抛出异常代码回滚异常会被全局异常捕获封装成code=10001的返回值只需要判断如果code值为10001抛出个异常就能回滚bill模块代码这样也可以实现多模块feign回滚