幂等键

业务标识号 +服务器时间戳 + 服务器编号 + 服务器生成的自增编号 + 用户标识序列号

流程图

image.png

时序图

image.png

表结构

用户表:
主键id
押金状态
账户余额

单号流水表:
主键id
单号,唯一索引
用户id,逻辑外键
钱的流向
状态

伪代码

  1. // 接收到请求
  2. public String 处理请求的函数(Integer id){
  3. int status = selectDepositStatusById(id);
  4. if ( 1 == status ){
  5. return // 已缴纳押金响应
  6. }else{
  7. // 创建单号
  8. String order = makeOrder(id);
  9. // 业务处理,返回结果
  10. return handleOrder();
  11. }
  12. }
  13. @Transaction
  14. public String handleOrder(String order,Integer id)
  15. // 开启事务向单号流水表插入单号
  16. try (){
  17. if (insertOrder(order)){
  18. if (doPay(order)){
  19. if (updateDepositStatusById(id)){
  20. // 成功缴纳押金
  21. // commit
  22. }else{
  23. // 押金可能已经缴纳,事务回滚
  24. }
  25. }else{
  26. // 支付失败,事务回滚
  27. }
  28. }
  29. }catch(唯一索引重复异常){
  30. // 订单已经处理,事务回滚
  31. }

问题

流程这里,当支付失败的时候,应该也放到业务单号表中,然后根据支付失败的原因进行决策,比如是因为网络原因还是余额不够,网络原因可能那边已经成功了,但是返回的结果不对(网络错误等),那么再次重试直到获取到结果。如果是余额不够,那么直接返回了,告诉用户余额不足。

当请求过来的时候,先去看看有没有该用户请求失败的订单,如果有,那么就先拿失败的订单请求,然后再根据结果判断。因为请求失败的原因可能有多种,包括网络延迟之类的。

会议记录

常用注解的熟悉
InetAddress.getLocalHost() 获取本地host地址
初始根据host去查询服务实例表中是否已经存在该服务:

  • 存在,返回实例的注册id
  • 不存在,注册服务

LocalDateTime.now()获取时间
String.format(“%03d”, yiId.getAndIncrement()%1000),格式化输出,位数不够时左侧填充0
流水表中失败的记录,要进行标识,下一次请求过来,先查询是否有失败记录,有,则先拿失败的进行请求,如果还是出现失败什么的,则可以定义一个提示函数,提示需要人工干预