前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >byteTCC框架--关于接口返回问题的讨论

byteTCC框架--关于接口返回问题的讨论

作者头像
IT云清
发布2019-03-04 16:06:59
9690
发布2019-03-04 16:06:59
举报
文章被收录于专栏:IT云清IT云清

在普通的web项目中,调用接口返回数据,如下,不出错返回一种,出错了,返回另外一种。前端是直接可以拿到返回的信息的。

  @GetMapping("decreaseMoney")
  @ResponseBody
  public void decreaseMoney(Integer id,BigDecimal money){
      try {
        //do something
        return "成功:something";
      }catch (Exception ex){
        ex.printStackTrace();
        return "失败:something";
      }
  }

但是引入byteTCC框架后,不能这么处理。因为事务是commit还是rollback,就是根据是否有异常来的控制事务走向的,如果try掉了,那事务最终都是会被commit的,就不会再rollback了。

关于这个问题的处理,请教了下byteTCC的维护者,非常耐心的回答了关于这个问题的疑问。这里记录下交流的这个过程,没有格式的是我提问的,有引用格式的是作者的回答:

对话

当调用失败后,我想拿到这个错误堆栈信息,怎么获取呢?我想把错误信息拿到存日志或者是返回

在这里插入图片描述
在这里插入图片描述

正常情况下,这个修改成功是可以返回到页面,但是调用出错时,这个return没法返回到页面

在这里插入图片描述
在这里插入图片描述

错误一般都是用异常来表示啊,用字符串表示很少见。你这个是用于显示的,但是SpringCloud更倾向于代表一个服务一个接口

比如我这个,一个服务调用了2个服务,其中一个出错了,我需要给前端一个反馈,但是我在这里没法拿到出错的那个服务的错误信息

那这种一般怎么处理呢

显示的内容更多的是由Web系统来负责的,微服务负责显示个人觉得不太合理,更何况,服务中的异常会改变事务完成方向呢,如果你把异常捕捉了返回一个字符串,事务就总是commit了。 你可以考虑抛出一个异常啊,不过如果ByteTCC在commit/rollback处理过程中也碰到异常,以事务异常优先抛出

现在出现异常时,页面直接就这样,实际开发中,这样处理不妥啊

在这里插入图片描述
在这里插入图片描述

这是ByteTCC在rollback过程中也碰到异常了,抛出的是SystemException 说错了,是在commit过程中 HTTP接口一般返回500码就能标识错误了,当然,如果你想在应用层面设置自己的业务异常码,可以考虑用Filter拦截这个接口然后转换,直接返回字符串肯定是不可以的

还是有点不懂,我们这习惯在正常时返回一种编码和结果,出错时在catch中返回一种编码和结果。意思是,我说的这种实现,这里是做不了的是吧。我看那个catch中的打印语句执行了,但是return未执行。

那就让前端自己判断状态码?

你这种做法不是不可以,只是说:在参与事务处理的controller中这样做不可以,不参与事务处理的controller中这样做是没问题的。原因也很简单,spring的声明式事务是要根据异常来判断事务是否commit/rollback的,如果业务把异常信息都自己吞掉了,那所有事务就都commit再也没有rollback了。。。 然后,再进一步的说,一般而言,SpringCloud的controller更倾向于就是一个接口(类似dubbo接口那种,提供的是一个服务能力),很大概率是要直接参与事务的,所以不建议这样做。但你要是一定让一个spring cloud接口做成显示的接口,倒也不是不行,那就别让它参与事务就好了

“spring的声明式事务是要根据异常来判断事务是否commit/rollback的,如果业务把异常信息都自己吞掉了,那所有事务就都commit再也没有rollback了”这句话,大概理解了,我try catch后,发现即使出错了,事务也commit了,导致数据变更了

这是spring声明式事务的机制,根据异常来判断是否需要回滚。没有异常时肯定就是提交了。 当然,也并不是说你在controller中抛出异常就只能显示那个500了,你可以考虑在框架层面对其进行处理,构建自己业务系统的业务异常码,只要在全局事务之外就可以

还有2个疑问:我A调用B和C服务,比如这里,bank服务调用user,company服务,那我这个接口中,bank不仅掉了b,c的接口,还调用自己本地的方法,那这个本地方法也是需要tcc逻辑的是吧?2.这个时候,b和c的controller中接口我不返回信息,那A这个接口,是要对页面提供返回值的,这种推荐怎么处理?

我个人比较推荐的做法是,就象你调用dubbo接口一样,如果没有实质的信息需要返回,那就别返回信息了。没异常就表示成功了,有异常consumer就会收到一个异常信息。至于页面显示什么,那是consumer收到成功/错误之后自己决定的,而不应该由provider来决定页面来显示什么 provider端接口返回一个“调用成功”、“调用失败”这中信息,是完全没有意义的。 HTTP接口,成功时200返回码就可以;返回4xx/5xx时就是失败了。在此基础上,你可以细化一下,比如你们希望所有的请求都返回200,但是错误时响应体内有failure-code,比如00000是成功,00001是创建订单失败,00002表示库存不足等等,可以考虑通过Filter在框架层面封装,而不是在controller中做这个事情

comsumer的接口,也不需要显式的返回信息,直接void,没问题就成功了,有问题的话,页面调用这个接口时,会直接拿到某种异常信息,判断下即可。可以这么简单的处理吗?或者,用filter来处理。这2种方式?

一般而言,微服务之间很少需要这样的封装,直接以异常或者HTTP返回码更适合,只有web系统和微服务之间,可能才需要这种方式,当然也不能一概而论,主要还是看业务系统自行规划 你可以参考一下ByteTCC的CompensableCoordinatorController的做法,出错时返回500,然后在header中加上错误的类型 注意,是说你的Filter可以参考CompensableCoordinatorController,业务Controller不能象CompensableCoordinatorController那样写,业务controller有错误需要回滚就要抛异常

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年02月15日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 对话
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档