处理由Mybatis缓存引发的存储执行结果异常问题

本文讲述了在使用Mybatis时遇到的一个问题,即当存储过程被多次调用且参数改变时,返回结果并未更新,原因是Mybatis缓存机制保存了引用对象而非值。通过分析源码,发现是缓存中存放的是同一对象引用,导致第二次调用时获取了错误的结果。解决方案包括设置`flushCache`为true或`useCache`为false,以及避免参数对象复用,确保每次传入新的对象。
摘要由CSDN通过智能技术生成

在一段代码中,需要根据不同的条件多次调用一个存储过程,后来发现后面的调用,尽管传入的参数改变了,返回的值依然没有变。

下面的代码在同一个代码块中被调用了两次,代码如下:

Map<String,Object> rm2 = new HashMap<String, Object>();
rm2.put("sectionId", map.get("sectionId"));
rm2.put("longitude", start.get("lng"));
rm2.put("latitude", start.get("lat"));

String savePile2 = sectionService.savePile2(rm2);

mm.putAll(map2);
//mm.put("startPile", savePile2);

rm2.put("longitude", end.get("lng"));
rm2.put("latitude", end.get("lat"));
String savePile3 = sectionService.savePile2(rm2);

代码作用为,根据经纬度获取某一天的起始&结束位置,由于要获取某一区间的起始&结束位置,当传入日期为区间起始日期时,根据起始日期获取到的这一天的起始&结束经纬度,上面的代码调用一次,获取这一天的起始&结束位置,比较后,取两者之间的较小值,作为起始日期的开始位置。然后在传入区间的终止日期,根据终止日期获取这一天的起始&结束经纬度,上面的代码再调用一次,获取这一天的起始&结束位置,比较后,取两者之间的较大值,作为终止日期的结束位置。

特殊情况下,区间太小,起始日期和终止日期为同一天,那么相当于把相同的代码执行了两次,结果第二次执行时,出问题了。第一次执行时,savePile2=k2,savePile3=k3,当第二次再调用上面的代码时,相同的参数,savePile2却反悔k3,并不是k2。怀疑是Mybatis的缓存影响的,跟踪源码如下:

(1)调用开始

  org.apache.ibatis.binding.MapperProxy.invoke(Object, Method, Object[])
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);  //----> 调用
  }

(2)

    org.apache.ibatis.binding.MapperMethod.execute(SqlSession, Object[])
    public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    if (SqlCommandType.INSERT == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.insert(command.getName(), param));
    } else if (SqlCommandType.UPDATE == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.update(command.getName(), param));
    } else if (SqlCommandType.DELETE == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.delete(command.getName(), param));
    } else if (SqlCommandType.SELECT == command.getType()) {
      if (method.returnsVoid() && method.hasResultHandler()) {
        executeWithResultHandler(sqlSession, args);
        result = null;
      } else if (method.returnsMany()) {
        result = executeForMany(sqlSession, args);
      } else if (method.returnsMap()) {
        result = executeForMap(sqlSession, args);
      } else {//存储过程,会执行到这里
        Object param = method.convertArgsToSqlCommandParam(args);
        result = sqlSession.selectOne(command.getName(), param);  //---> 调用
      }
    } else if (SqlCommandType.FLUSH == command.getType()) {
        result = sqlSession.flushStatements();
    } else {
      throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new Binding
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值