当前位置:首页 > 科技  > 软件

盘点 Mybatis 使用过程中遇到的坑!

来源: 责编: 时间:2024-09-10 09:47:53 223观看
导读01、引言大家好,我是了不起,前一段时间在工作中因为一个疏忽踩了一个坑,最终通过异常栈追溯源码解决了问题。下面我来给大家还原一下案发现场,并介绍一下自己的解决思路,希望能对大家有所启发。02、案发现场当时的业务逻辑

01、引言

大家好,我是了不起,前一段时间在工作中因为一个疏忽踩了一个坑,最终通过异常栈追溯源码解决了问题。dtB28资讯网——每日最新资讯28at.com

下面我来给大家还原一下案发现场,并介绍一下自己的解决思路,希望能对大家有所启发。dtB28资讯网——每日最新资讯28at.com

02、案发现场

当时的业务逻辑主要通过 Mybatis 框架来修改数据,具体示例如下:dtB28资讯网——每日最新资讯28at.com

import org.springframework.data.repository.query.Param;public interface GroupMapper {  int updateGroup(@Param("oldSerial") Set<Integer> oldSerial, @Param("newSerial") int newSerial); int invalidGroup(@Param("set") Set<Integer> set);}
<update id="updateGroup">    update groupCode_table_use    set groupCode=#{newSerial}    where groupCode in    <foreach collection="oldSerial" close=")" open="(" item="item" separator=",">        #{item}    </foreach></update><update id="invalidGroup">    update groupCode_table    set status='无效'    where groupCode in    <foreach collection="set" close=")" open="(" item="item" separator=",">        #{item}    </foreach></update>

本以为 so easy 的代码,出现意外了!第一个sql语句updateGroup正常运行,第二个sql语句invalidGroup竟然报错了???dtB28资讯网——每日最新资讯28at.com

报错信息如下:dtB28资讯网——每日最新资讯28at.com

图片图片dtB28资讯网——每日最新资讯28at.com

从日志上可以看出,提示set参数找不到!dtB28资讯网——每日最新资讯28at.com

明明使用了@Param("set")将参数命名为set为何找不到,完全不符合多年开发的认知。dtB28资讯网——每日最新资讯28at.com

更加诡异的是updateGroup已使用了同样的方式去遍历,完全没得问题,那么问题出现在了哪了?dtB28资讯网——每日最新资讯28at.com

小伙伴可以先猜一猜!dtB28资讯网——每日最新资讯28at.com

03、原因分析

百思不得其解下,我掏出了祖传绝活 debug 源码,最终发现原来是Mybatis对集合Set进行了特殊处理。dtB28资讯网——每日最新资讯28at.com

案发项目引入的Mybatis版本是 3.5.1。部分源码如下!dtB28资讯网——每日最新资讯28at.com

org.apache.ibatis.session.defaults.DefaultSqlSession.java@Overridepublic int update(String statement, Object parameter) {  try {    dirty = true;    MappedStatement ms = configuration.getMappedStatement(statement);    //调用了wrapCollection方法对参数进行了处理    return executor.update(ms, wrapCollection(parameter));  } catch (Exception e) {    throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);  } finally {    ErrorContext.instance().reset();  }}/*** 如果参数实现了Collection接口或是数组类型 wrapCollection方法会对参数进行封装* 如果参数实现了Collection接口会封装为含collection键的Map*     如果参数又实现了List接口会封装为含list键的Map(追增)*     对Set集合没有特殊处理* 如果参数是数组类型会封装为含array键的Map*/private Object wrapCollection(final Object object) {  if (object instanceof Collection) {    StrictMap<Object> map = new StrictMap<>();    map.put("collection", object);    if (object instanceof List) {      map.put("list", object);    }    return map;  } else if (object != null && object.getClass().isArray()) {    StrictMap<Object> map = new StrictMap<>();    map.put("array", object);    return map;  }  return object;}

通过以上的源码分析,发现Mybatis框架对集合参数进行了特殊处理。dtB28资讯网——每日最新资讯28at.com

这就是为什么报错信息中提示Available parameters are [collection]。dtB28资讯网——每日最新资讯28at.com

找到了collection错误信息从哪里来问题,接下来我们分析一下set参数到了哪里去。dtB28资讯网——每日最新资讯28at.com

首先updateGroup可以正常执行是因为源码中对集合的特殊处理只对单参数生效,也就是说@Param("set")注解失效是因为被Mybatis自家的特殊处理给覆盖了?dtB28资讯网——每日最新资讯28at.com

这不合乎常理啊,那么问题可能出在@Param注解身上,通过排查代码发现GroupMapper.java类引用的@Param注解不对!dtB28资讯网——每日最新资讯28at.com

// 代码引入的注解类Paramimport org.springframework.data.repository.query.Param;// 期望的注解类,应该由mybatis提供import org.apache.ibatis.annotations.Param;

实际上,springframework包下的@Param注解执行时机在wrapCollection处理之前,wrapCollection对集合的特殊处理将springframework包下的@Param注解处理覆盖掉了,所以无法解析参数set。而mybatis包下的@Param注解执行时机在wrapCollection处理之后,程序可以正常运行。dtB28资讯网——每日最新资讯28at.com

最终确定,绕了这么大一圈,原来是包导入错了,谁能想到springframework包下还有一个@Param注解,在多参数的情况下竟然可以正常使用o(╥﹏╥)o。dtB28资讯网——每日最新资讯28at.com

04、异常栈分析法

整个异常排查过程中,主要通过分析异常栈信息进行快速定位。下面我给大家介绍一下异常栈分析法。dtB28资讯网——每日最新资讯28at.com

我们在工作中查看异常栈,往往都是业务代码异常导致的,这个时候我们只需要关心是在我们编写的哪段代码中出了问题。dtB28资讯网——每日最新资讯28at.com

而这时好用的idea也会为温馨的为我们做出提示,会在异常栈中将我们编写的方法位置信息标蓝处理,这样我们就定快速定位出现问题的代码。dtB28资讯网——每日最新资讯28at.com

图片图片dtB28资讯网——每日最新资讯28at.com

但是一旦是底层引用的jar包出现了异常,仅仅是这样查看异常栈是不够的。下面我们就以上面案例中的异常栈来带大家分析。dtB28资讯网——每日最新资讯28at.com

当前异常:dtB28资讯网——每日最新资讯28at.com

图片图片dtB28资讯网——每日最新资讯28at.com

原始异常:dtB28资讯网——每日最新资讯28at.com

图片图片dtB28资讯网——每日最新资讯28at.com

分析流程:dtB28资讯网——每日最新资讯28at.com

  • 异常调用栈顺序:从上至下为方法调用顺序的逆序,异常由异常栈的最上面的方法抛出,整个调用的入口在最下方。
  • 寻找原始异常入口技巧:检索异常栈中与原始异常入口(最下面)抛出位置同名的方法。
  • 寻找真正异常出现的位置,要找最后一个 Caused by 的第一行栈帧。


dtB28资讯网——每日最新资讯28at.com

"Caused by" 是 Java 异常处理机制中的一部分,它表示当前异常是由另一个异常引起的。在 Java 中,每个 Throwable 对象都可以通过 getCause() 方法获取到原始异常,这个原始异常就是通过 "Caused by" 打印出来的。dtB28资讯网——每日最新资讯28at.com

异常栈示例代码:

假设你在catch块中捕获了一个异常,并重新抛出了一个新的异常,同时保留了原始异常的信息:dtB28资讯网——每日最新资讯28at.com

public class Example {    public static void main(String[] args) {        try {            methodThatThrowsException();        } catch (Exception e) {            throw new RuntimeException("Caught an exception", e);        }    }    public static void methodThatThrowsException() throws Exception {        throw new Exception("Original exception");    }}

当你运行上述代码时,控制台输出的异常栈信息通常会包含Caused by信息:dtB28资讯网——每日最新资讯28at.com

java.lang.RuntimeException: Caught an exception    at Example.main(Example.java:7)Caused by: java.lang.Exception: Original exception    at Example.methodThatThrowsException(Example.java:12)    at Example.main(Example.java:5)
  • java.lang.Exception: Original exception 是原始异常。
  • java.lang.RuntimeException: Caught an exception 是新抛出的异常,并且包含了原始异常作为其原因。
  • Caused by 信息显示了原始异常的详细信息,这有助于调试和理解异常的来源。

如何保留原始异常信息呢?dtB28资讯网——每日最新资讯28at.com

  • 方式一:直接传递原始异常:
try {     methodThatThrowsException(); } catch (Exception e) {     throw new RuntimeException("Caught an exception", e); }
  • 方式二:使用 addSuppressed 方法:
try {     methodThatThrowsException(); } catch (Exception e) {     RuntimeException newException = new RuntimeException("Caught an exception");     newException.addSuppressed(e);     throw newException; }

05、结语

学会查看分析异常栈,可以为我们工作大大提高效率,希望这篇文章给大家带来收获,最后再送给大家一个小技巧。异常栈不仅仅可以用来排查异常哦,还可以帮助大家学习源码,debug 源码找不到入口怎么办,那就创造一个异常!dtB28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-112730-0.html盘点 Mybatis 使用过程中遇到的坑!

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: SpringBoot与XXL-JOB高效定时任务管理指南

下一篇: Elasticsearch 使用误区—单次请求获取大量数据

标签:
  • 热门焦点
  • 俄罗斯:将审查iPhone等外国公司设备 保数据安全

    iPhone和特斯拉都属于在各自领域领头羊的品牌,推出的产品也也都是数一数二的,但对于一些国家而言,它们的产品可靠性和安全性还是在限制范围内。近日,俄罗斯联邦通信、信息技术
  • 影音体验是真的强 简单聊聊iQOO Pad

    大公司的好处就是产品线丰富,非常细分化的东西也能给你做出来,例如早先我们看到了新的vivo Pad2,之后我们又在iQOO Neo8 Pro的发布会上看到了iQOO的首款平板产品iQOO Pad。虽
  • 6月安卓手机性价比榜:Note 12 Turbo断层式碾压

    6月份有一个618,虽然这是京东周年庆的日子,但别的电商也都不约而同的跟进了,反正促销没坏处,厂商和用户都能满意。618期间一些产品也出现了历史低价,那么各个价位段的产品性价比
  • Flowable工作流引擎的科普与实践

    一.引言当我们在日常工作和业务中需要进行各种审批流程时,可能会面临一系列技术和业务上的挑战。手动处理这些审批流程可能会导致开发成本的增加以及业务复杂度的上升。在这
  • 阿里大调整

    来源:产品刘有媒体报道称,近期淘宝天猫集团启动了近年来最大的人力制度改革,涉及员工绩效、层级体系等多个核心事项,目前已形成一个初步的&ldquo;征求意见版&rdquo;:1、取消P序列
  • 网传小米汽车开始筛选交付中心 建筑面积不低于3000平方米

    7月7日消息,近日有微博网友@长三角行健者爆料称,据经销商集团反馈,小米汽车目前已经开始了交付中心的筛选工作,要求候选场地至少有120个车位,建筑不能低
  • 首发天玑9200+ iQOO Neo8系列发布首销售价2299元起

    2023年5月23日晚,iQOO Neo8系列正式发布。其中,Neo系列首款Pro之作——iQOO Neo8 Pro强悍登场,限时售价3099元起;价位段最强性能手机iQOO Neo8同期上市
  • 机构称Q2全球智能手机出货量同比下滑11% 苹果份额依旧第2

    7月20日消息,据外媒报道,研究机构的报告显示,由于需求下滑,今年二季度全球智能手机的出货量,同比下滑了11%,三星、苹果等主要厂商的销量,较去年同期均有下
  • 由于成本持续增加,笔记本产品价格预计将明显上涨

    根据知情人士透露,由于材料、物流等成本持续增加,笔记本产品价格预计将在2021年下半年有明显上涨。进入6月下旬以来,全球半导体芯片缺货情况加剧,显卡、处理器
Top