MyBatis-Plus 中 Mapper 重载踩坑指南
共 2648字,需浏览 6分钟
· 2021-08-23
前言
近期在 Mapper 中写了个方法重载,然后死活查不到正确结果,最终灵机一动,想到是不是因为重载,然后我 Shift + F6
把重载方法名字改了一下!结果,显而易见,重载的那个方法也一块改了。再次躺坑!
1
背景
以下为模式测试数据
MySQL 表
![](https://filescdn.proginn.com/e19c1b1f98b35d01dcf52a6a6dd3ba01/4df2b32b503b8fd87526050ab3bd5706.webp)
Mapper
![](https://filescdn.proginn.com/d62df10b5f85899b8f2848a9793b356d/f4136872fa0a60ab37c89d3d8a17b20e.webp)
如果看到这里,已经发现了问题,并知道原因,那可以直接跳过,进行三连即可。
当然,在 Mapper.xml 这么写,会提示错误(插件功能)
![](https://filescdn.proginn.com/b3cb99e2b41c6fcfe4e81da14009a814/2c16b4bab18737a44b03b89c6494205c.webp)
Junit
![](https://filescdn.proginn.com/753f71014c9ee579013c9f808145bc1e/2932e2204b460f79e0a55be33955588c.webp)
执行结果是:
sum=1500 sumWithTime=1500
这就神奇了,没有报错,结果竟然是相同的
。
版本依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.2</version>
</dependency>
mybatis-plus-boot-starter 3.1.2 对应的是 mybatis:3.5.1 和 mybatis-spring:2.0.1
3
深入排查
MyBatis-Plus
两个结果相同,那就断点断到第二个上面,debug 进去,看看执行过程。
![](https://filescdn.proginn.com/702585861b13b600391f0d85f5d2c63e/6c117527d892d530378400b19e75d305.webp)
F7 进入!这里直接进到 com.baomidou.mybatisplus.core.override.MybatisMapperProxy#invoke
![](https://filescdn.proginn.com/54199eacb1ec2d5543498dd2a8c9b8bd/8c5a7f176f0416a1d67a7681030a0c91.webp)
这里都是 mybatis-plus 的代理。
进入跟进,进入到 com.baomidou.mybatisplus.core.override.MybatisMapperMethod#execute
![](https://filescdn.proginn.com/b64ac87a943ea6e05702aed0cdc6a5df/fad2ef80f5cb94963caa51af49cce44e.webp)
这里相当于执行
Object result = sqlSession.selectOne("com.liuzhihang.demo.mapper.TransOrderMapper.sumOrderAmount", param);
后面就是进入 Mybatis 的环节了。
![](https://filescdn.proginn.com/3ace01678097548edd7793a4005cf668/b7581cc835e514713751b720e961bcae.webp)
在这里会进入 Mybatis 的 slectList 方法(org.apache.ibatis.session.defaults.DefaultSqlSession#selectList
)。
![](https://filescdn.proginn.com/ceefea326b420d24f8b165310c1b2f0a/926010a4442a3745fed8a79e3d9e8c43.webp)
从 configuration
中生成所有的 mappedStatements,然后从 statements 中获取根据 id,也就是方法的全路径,获取当前的 statements。
![](https://filescdn.proginn.com/33c4908894565dad0de2fe0a86ea6b4d/feed759577cc39c4eac871020a34e300.webp)
先看看 mappedStatements 里面都有啥?
![](https://filescdn.proginn.com/1564a38f8a77569e185a06096ca18f66/48286aa68b421f8ba1276f7346ea7137.webp)
mappedStatements 是一个 Map 结构! 其中 key 是方法名,value 是一个 MappedStatement
所以这里的意思是根据方法的全路径名称,获取一个 MappedStatement, 而 com.liuzhihang.demo.mapper.TransOrderMapper.sumOrderAmount
在这里面只有一个。
![](https://filescdn.proginn.com/1fed889081ebfe76a556c557ac0ea0ec/eb464695738953e367fa9ab7932d95f7.webp)
所以最终执行的 sql 是 select ifnull(sum(order_amount),0) from trans_order where user_id = ? ;
。这也是为什么两个方法执行的结果是相同的了。
究其原因,则是因为 configuration 中就没有重载方法的 MappedStatement
而根本原因则是在 com.baomidou.mybatisplus.core.MybatisConfiguration#addMappedStatement
中写了一段代码!
![](https://filescdn.proginn.com/5b37a31a0913eb019af5039f34b81739/6375de188fdde3b54bff9e6d55b5cadc.webp)
如果已经存在,则直接忽略,同时会打印日志。
mapper[xxx] is ignored, because it exists, maybe from xml file
MyBatis
那如果使用原生 MyBatis 呢?
其实会在启动阶段就报错,服务直接启动失败。
![](https://filescdn.proginn.com/7bb995647844eed6e964f9543bb3bad6/f4ffc6253a59886c0db2d9b6812a84ec.webp)
其中异常是:
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
![](https://filescdn.proginn.com/18d9cb3d6a12862b16e138d52dfa8111/f5b235024770eb246b46c340642ae89a.webp)
而第二次重载方法,来的时候就会抛出异常。
3
总结
在 MyBatis-Plus 中 Mapper 重载并不会出现异常,但是查询结果都是相同的。因为 MyBatis-Plus 的 MybatisConfiguration 继承重写了 MyBatis Configuration 的 addMappedStatement 方法。 在 MyBatis-Plus 中发现该 MappedStatement 已经存在,则不进行添加。 而在 MyBatis 中如果 MappedStatement 如果 key 存在,则直接抛出异常,服务启动失败。
以上就是我经历的一个小坑,也是因为个人图省事,写了个重载。虽然记得不能重载,但是看启动没问题,就觉得 ok。
- <End /> -
历史文章 | 相关推荐