MyBatis-Plus 中 Mapper 重载踩坑指南

MyBatis-Plus 中 Mapper 重载踩坑指南_第1张图片

前言

近期在 Mapper 中写了个方法重载,然后死活查不到正确结果,最终灵机一动,想到是不是因为重载,然后我 Shift + F6 把重载方法名字改了一下!结果,显而易见,重载的那个方法也一块改了。再次躺坑!

1

背景

以下为模式测试数据

  • MySQL 表

MyBatis-Plus 中 Mapper 重载踩坑指南_第2张图片
  • Mapper

MyBatis-Plus 中 Mapper 重载踩坑指南_第3张图片

如果看到这里,已经发现了问题,并知道原因,那可以直接跳过,进行三连即可。

当然,在 Mapper.xml 这么写,会提示错误(插件功能)

MyBatis-Plus 中 Mapper 重载踩坑指南_第4张图片
  • Junit

MyBatis-Plus 中 Mapper 重载踩坑指南_第5张图片

执行结果是:

sum=1500 sumWithTime=1500

这就神奇了,没有报错,结果竟然是相同的

版本依赖

    com.baomidou
    mybatis-plus-boot-starter
    3.1.2

mybatis-plus-boot-starter 3.1.2 对应的是 mybatis:3.5.1 和 mybatis-spring:2.0.1

3

深入排查

MyBatis-Plus

两个结果相同,那就断点断到第二个上面,debug 进去,看看执行过程。

MyBatis-Plus 中 Mapper 重载踩坑指南_第6张图片

F7 进入!这里直接进到 com.baomidou.mybatisplus.core.override.MybatisMapperProxy#invoke

MyBatis-Plus 中 Mapper 重载踩坑指南_第7张图片

这里都是 mybatis-plus 的代理。

进入跟进,进入到 com.baomidou.mybatisplus.core.override.MybatisMapperMethod#execute

MyBatis-Plus 中 Mapper 重载踩坑指南_第8张图片

这里相当于执行

Object result = sqlSession.selectOne("com.liuzhihang.demo.mapper.TransOrderMapper.sumOrderAmount", param);

后面就是进入 Mybatis 的环节了。

MyBatis-Plus 中 Mapper 重载踩坑指南_第9张图片

在这里会进入 Mybatis 的 slectList 方法(org.apache.ibatis.session.defaults.DefaultSqlSession#selectList)。

MyBatis-Plus 中 Mapper 重载踩坑指南_第10张图片

从 configuration 中生成所有的 mappedStatements,然后从 statements 中获取根据 id,也就是方法的全路径,获取当前的 statements。

MyBatis-Plus 中 Mapper 重载踩坑指南_第11张图片

先看看 mappedStatements 里面都有啥?

MyBatis-Plus 中 Mapper 重载踩坑指南_第12张图片
  1. mappedStatements 是一个 Map 结构!

  2. 其中 key 是方法名,value 是一个 MappedStatement

所以这里的意思是根据方法的全路径名称,获取一个 MappedStatement, 而 com.liuzhihang.demo.mapper.TransOrderMapper.sumOrderAmount 在这里面只有一个。

MyBatis-Plus 中 Mapper 重载踩坑指南_第13张图片

所以最终执行的 sql 是 select ifnull(sum(order_amount),0) from trans_order where user_id = ? ;。这也是为什么两个方法执行的结果是相同的了。

究其原因,则是因为 configuration 中就没有重载方法的 MappedStatement

而根本原因则是在 com.baomidou.mybatisplus.core.MybatisConfiguration#addMappedStatement 中写了一段代码!

MyBatis-Plus 中 Mapper 重载踩坑指南_第14张图片

如果已经存在,则直接忽略,同时会打印日志。

mapper[xxx] is ignored, because it exists, maybe from xml file

MyBatis

那如果使用原生 MyBatis 呢?

其实会在启动阶段就报错,服务直接启动失败。

493f9070ba86737e04fbb0b505b20925.png

其中异常是:

java.lang.IllegalArgumentException: Mapped Statements collection already contains value xxx

进入源码,org.apache.ibatis.session.Configuration#addMappedStatement

在这里会创建 mappedStatements,调用的是 Map 的 put 方法。

Configuration.StrictMap#put 继承了 HashMap 具体内容不细看。

其中 key 的结构是方法的方法全路径。比如 com.liuzhihang.demo.mapper.TransOrderMapper.sumOrderAmount

MyBatis-Plus 中 Mapper 重载踩坑指南_第15张图片

而第二次重载方法,来的时候就会抛出异常。

3

总结

  1. 在 MyBatis-Plus 中 Mapper 重载并不会出现异常,但是查询结果都是相同的。因为 MyBatis-Plus 的 MybatisConfiguration 继承重写了 MyBatis Configuration 的 addMappedStatement 方法。

  2. 在 MyBatis-Plus 中发现该 MappedStatement 已经存在,则不进行添加。

  3. 而在 MyBatis 中如果 MappedStatement 如果 key 存在,则直接抛出异常,服务启动失败。

以上就是我经历的一个小坑,也是因为个人图省事,写了个重载。虽然记得不能重载,但是看启动没问题,就觉得 ok。

- -


历史文章 | 相关推荐

  • 使用 Maven Archetype 创建项目模版

  • Spring 自调用事务失效,你是怎么解决的?

  • 并发场景加锁优化小技巧

2d2bc37ed13c613653fe9e1e4dcbeea7.gif

你可能感兴趣的:(java,spring,mybatis,zookeeper,maven)