请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

如何优雅的进行重试

问题描述

老师您好,最近在工作中遇到这样一种情况,执行某行代码的时候可能会发生某种异常,通常来说,我可以在catch块中自行解决,然后再把这行代码写一遍来执行,但这样做我认为有两个问题

  1. 不够优雅
  2. 如果在catch块的代码再次出错我将无法处理,除非再次进行try catch

实际问题再现

背景

使用jdbcTemp向数据表中插入数据

jdbcTemplate.update("insert into TABLE_NAME (NAME, SEX, CITY, AGE) values (?,?,?,?)", values.toArray());

问题

当执行上面这行代码的时候,当然,此时可能会发生很多运行时异常,比如表不存在,数据库连不上等等,但在我的项目中,最有可能出现的是“标识符无效”这个异常,意思就是说现在的sql语句中有4个字段要被插入,可是在执行的时候却发现某个字段当前并不存在于数据表中,假设当前目标表只有两个字段,NAME和SEX,那么就会提示“CITY 标识符无效”。

我的做法

最初,我认为这个问题很好解决,因为可以通过e.getMessage()获得具体是哪个字段还不存在的错误提示,那么只需要在捕获到异常后继续在异常中修改一下表结构,缺啥补啥呗,再执行一下修改表结构的语句加个字段就好了

alter table TABLE_NAME
	add CITY varchar(32)
/

表结构修改后再运行一下插入语句就好了。
但是,
当前抛出的错误只能知道一个缺少的字段,再次执行插入语句时,还会提示“AGE标识符无效”,所以实际情况有可能是很多字段都缺少。

我的想法

现在这个问题被我从另一个层面解决了,就是一旦捕获到标识符异常时,就去select一下表,查询到当前存在的字段,然后把本次插入的字段减掉当前存在的字段,剩下的就是需要add的字段,进行修改表结构,然后再执行一开始的插入语句。

但是,我真正希望的其实是这样的一种机制:

try
{
    jdbcTemplate.update(sql语句, values.toArray());
}
catch (DataAccessException e)
{
    //捕获到错误
    //尝试进行修复
    //自动重新执行之前的代码,如果还是报错,则循环这一过程
}

其实思考到这里我也发现了问题所在,这只是一种理想的模型,或者说是一种只适用于当前情况的模型,java目前的异常机制似乎不能直接实现这个过程。

另一个实际问题

在遇到这个问题之后,总结出来的机制应该会稍稍好一些,那就是多了重试次数(重试次数这个东西只适用于发起网络请求的情况,而不适用上面未知要重试多少次的情况)

背景

使用第三方公司提供的SDK发送请求获得返回,可是对方的服务不稳定,经常性的超时,超时的情况下,调用sdk的方法返回的就是一个null。当我接下来的程序如果拿到一个null,那么我就要重新发起请求,而重试次数则是我写死的,这一过程被我写在了一个for循环中。

 private static String getHKSDKResult(String contentType, JSONObject reqBody, Map<String, String> path, int retryNumber, String hkSDKResult)
    {
        String s = null;
        for (int i = 1; i <= retryNumber; i++)
        {
            s = ArtemisHttpUtil.doPostStringArtemis(path, reqBody.toStringPretty(), null, null, contentType, null);
            if (s == null)
            {
                log.error("SDK请求发生错误,无法正确返回!");
                log.error("reqBody:{}\n", reqBody.toStringPretty());
                if (retryNumber != 1)
                {
                    log.error("\n进行第{}次重试", i);
                }
                continue;
            }
            if (s != null && JSONUtil.isJson(s))
            {
                hkSDKResult = s;
                break;
            }
            else
            {
                log.error("海康SDK请求返回了,但不为一个json");
                log.error("返回内容:{}", hkSDKResult);
                log.error("reqBody:{}", reqBody.toStringPretty());
                log.error("\n进行第{}次重试", i);
            }
        }
        return hkSDKResult;
    }

这里由于使用了SDK,并没有抛出异常来进行处理,但在我的业务逻辑中,拿到null其实就相当于报错了,我需要重试,我想知道类似的情形,有没有更好更优雅的处理办法呢?

正在回答

1回答

同学你好:

    关于重试,其实不需要自己去想特别复杂的逻辑实现。这样的场景有很多开源实现可以去做:speing retry 或者是 guava retry 就可以。

1 回复 有任何疑惑可以回复我~
  • 提问者 乃好 #1
    非常感谢!
    回复 有任何疑惑可以回复我~ 2021-11-22 15:21:09
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信