Redis,数据库,MQ,文件服务等 多个资源的业务操作事务一致性思路

public interface Service{
  //业务方法
  doBusiness();
  //数据库更新方法
  doBusinessTX();
}

@Service
public class ServiceImpl implements Service,ApplicationContextAware{

  //自己注入自己由IOC Container解决循环依赖
  @Autowired
  private Service ServiceProxy;

  //或者使用Aware接口获取BeanFactory获取当前对象事务代理对象 Aware接口动作逻辑由IOC扩展点接口BeanPostProcessor来执行
  @Override
  public void setApplicationContext(ApplicationContext ctx) throws BeansException{
    this.Service = ctx.getBean(Service.class);
  }
  @Transactional(rollback
=RuntimeException.class)//默认RuntimeException和虚拟机Error回滚   public void doBusinessTX(){     数据库更新 可抛出RuntimeException 自动触发数据库回滚     return;   }   public void operateRedis(){     //redisTemplate.eval 涉及多个KEY操作使用LUA脚本   }   public void operateRedisRollback(){     //redisTemplate.eval 执行LUA脚本 多个KEY同时操作 原子执行 回退redis修改   }   public void operateMQ() throws MQException{     //发送MQ 捕捉RuntimeException 转换为MQException再抛出 其他异常转换为MQException   }   @Override   public void doBusiness(){     try{       this.operateRedis();//redis逻辑 脚本串行化执行立即生效 脚本中需要相应校验条件成功然后执行并返回相应的状态码       this.ServiceProxy.doBusinessTX();//数据库逻辑 需判断上步redis返回的状态码 并由代理对象调用声明事务方法 方法调用结束数据库事务生效       this.operateMQ();//MQ逻辑 最后发送 此时redis和数据库已生效 如MQ失败可能需重新发送 (retry) 如重发仍失败可则抛出MQException 而对可能产生的RuntimeException需将之转换为MQException     }catch(RuntimeException e){       //处理运行时异常 数据库回滚异常 此时数据库已自动回滚需显式回滚redis 仍使用脚本串行化执行回退立即生效       this.operateRedisRollback();     }catch(MQException me){       //MQException 最后发送MQ 如果是先发送MQ 则可能涉及redis或者数据库逻辑失败 需要再发送撤销MQ 这可能导致已发出MQ的关联业务回退 增加交互复杂性
      //如先发送MQ等待redis和数据库业务成功后确认 则redis和数据逻辑务期间占用MQ链接而不commit 效果同最后发送MQ
      //如最后发送MQ重试多次仍失败 一般可将业务状态置为异常 需后续冲正或异步任务处理或者延迟发送
      //如果还有类似文件服务的操作 一般不将耗时或耗费资源IO操作放在数据库事务中 可异步调起文件服务操作 并可使用类似信号量作相应限制
    }finally{     }   } }
posted @ 2021-08-03 18:30  棠棣~  阅读(186)  评论(0)    收藏  举报