目录

  • 前言
  • 环境配置
  • 错误示范
  • 为什么不能重载?
  • 如何找到XML中对应的SQL?
  • 总结

前言

  • 在初入门Mybatis的时候可能都犯过一个错误,那就是在写Mapper接口的时候都重载过其中的方法,但是运行起来总是报错,那时候真的挺郁闷的,但是自己也查不出来原因,只能默默的改了方法名,哈哈,多么卑微的操作。
  • 今天就写一篇文章从源码角度为大家解惑为什么Mybatis中的方法不能重载?

环境配置

  • 本篇文章讲的一切内容都是基于Mybatis3.5SpringBoot-2.3.3.RELEASE

错误示范

  • 举个栗子:假设现在有两个需求,一个是根据用户的id筛选用户,一个是根据用户的性别筛选,此时在Mapper中重载的方法如下:
public interface UserMapper {
List<UserInfo> selectList(@Param("userIds") List<String> userIds); List<UserInfo> selectList(Integer gender);
}
  • 这个并没有什么错误,但是启动项目,报出如下的错误:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactory' threw exception; nested exception is org.springframework.core.NestedIOException: Failed to parse mapping resource: 'file [H:\work_project\demo\target\classes\mapper\UserInfoMapper.xml]'; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'file [H:\work_project\demo\target\classes\mapper\UserInfoMapper.xml]'. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for cn.cb.demo.dao.UserMapper.selectList. please check file [H:\work_project\demo\target\classes\mapper\UserInfoMapper.xml] and file [H:\work_project\demo\target\classes\mapper\UserInfoMapper.xml]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:635)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1176)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1307)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1509)
... 81 more
  • 这么一大串什么意思?懵逼了~

  • 大致的意思:cn.cb.demo.dao.UserMapper.selectList这个id已经存在了,导致创建sqlSessionFactory失败。

为什么不能重载?

  • 通过上面的异常提示可以知道创建sqlSessionFactory失败了,这个想必已经不陌生吧,顾名思义,就是创建SqlSession的工厂。
  • Springboot与Mybatis会有一个启动器的自动配置类MybatisAutoConfiguration,其中有一段代码就是创建sqlSessionFactory,如下图:
  • 既然是创建失败,那么肯定是这里出现异常了,这里的「大致思路」就是:

解析XML文件和Mapper接口,将Mapper中的方法与XML文件中<select><insert>等标签一一对应,那么Mapper中的方法如何与XML中<select>这些标签对应了,当然是唯一的id对应了,具体如何这个id的值是什么,如何对应?下面一一讲解。

  • 如上图的SqlSessionFactory的创建过程中,前面的部分代码都是设置一些配置,并没有涉及到解析XML的内容,因此答案肯定是在最后一行return factory.getObject();,于是此处打上断点,一点点看。于是一直到了org.mybatis.spring.SqlSessionFactoryBean#buildSqlSessionFactory这个方法中,其中一段代码如下:
  • 这里的xmlMapperBuilder.parse();就是解析XML文件与Mapper接口,继续向下看。
  • 略过不重要的代码,在org.apache.ibatis.builder.xml.XMLMapperBuilder#configurationElement这个方法中有一行重要的代码,如下图:
  • 此处就是根据XML文件中的select|insert|update|delete这些标签开始构建MappedStatement了。继续跟进去看。
  • 略过不重要的代码,此时看到org.apache.ibatis.builder.MapperBuilderAssistant#addMappedStatement这个方法返回值就是MappedStatement,不用多说,肯定是这个方法了,仔细一看,很清楚的看到了构建id的代码,如下图:
  • 从上图可以知道,创建id的代码就是id = applyCurrentNamespace(id, false);,具体实现如下图:

上图的代码已经很清楚了,MappedStatement中的id=Mapper的全类名+'.'+方法名。如果重载话,肯定会存在id相同的MappedStatement

  • 到了这其实并不能说明方法不能重载啊,重复就重复呗,并没有冲突啊。这里需要看一个结构,如下:
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
  • 构建好的MappedStatement都会存入mappedStatements中,如下代码:
public void addMappedStatement(MappedStatement ms) {
//key 是id
mappedStatements.put(ms.getId(), ms);
}
  • StrictMapput(k,v)方法如下图:

到了这里应该理解了吧,这下抛出的异常和上面的异常信息对应起来了吧。这个StrictMap不允许有重复的key,而存入的key就是id。因此Mapper中的方法不能重载。

如何找到XML中对应的SQL?

  • 在使用Mybatis的时候只是简单的调用Mapper中的方法就可以执行SQL,如下代码:
List<UserInfo> userInfos = userMapper.selectList(Arrays.asList("192","198"));

一行简单的调用到底如何找到对应的SQL呢?其实就是根据idMap<String, MappedStatement> mappedStatements中查找对应的MappedStatement

  • org.apache.ibatis.session.defaults.DefaultSqlSession#selectList方法有这一行代码如下图:
  • MappedStatement ms = configuration.getMappedStatement(statement);这行代码就是根据idmappedStatements获取对应的MappedStatement,源码如下:
public MappedStatement getMappedStatement(String id) {
return this.getMappedStatement(id, true);
}

总结

  • 文章写到这,想必已经很清楚Mapper中的方法为什么不能重载了,归根到底就是因为这个这个id=Mapper的全类名+'.'+方法名
  • 如果觉得作者写的不错,有所收获的话,点点关注,分享一波,关注微信公众号码猿技术专栏第一手文章推送!!!

Mybatis的Mapper中的方法为什么不能重载?的更多相关文章

  1. Mybatis接口Mapper内的方法为啥不能重载吗?

    动态代理的功能:通过拦截器方法回调,对目标target方法进行增强. 言外之意就是为了增强目标target方法.上面这句话没错,但也不要认为它就是真理,殊不知,动态代理还有投鞭断流的霸权,连目标tar ...

  2. Mybatis的mapper代理开发方法

    一.开发规范 1.映射文件中的namespase等于mapper接口类路径 2.statement的id与mapper中的方法名一致 3.让mapper的接口方法输入参数类型与statement中的p ...

  3. mybatis的mapper中,实体非空检验问题

    因为项目变动,数据库需要删除一个字段,于是勤劳的我把项目中对应的实体属性也给弄掉了,可是没有弄彻底,mybatis里面的mapper没有管,当时感觉是选择性的插入: <if test=" ...

  4. mybatis的Mapper代理原理

    前言:在mybatis的使用中,我们会习惯采用XXMapper.java+XXMapper.xml(两个文件的名字必须保持一致)的模式来开发dao层,那么问题来了,在XXMapper的文件里只有接口, ...

  5. 四. Java继承和多态3. 继承中的方法的覆盖和重载

    在类继承中,子类可以修改从父类继承来的方法,也就是说子类能创建一个与父类方法有不同功能的方法,但具有相同的名称.返回值类型.参数列表. 如果在新类中定义一个方法,其名称.返回值类型和参数列表正好与父类 ...

  6. 关于Mybatis的@Param注解 及 mybatis Mapper中各种传递参数的方法

    原文:https://blog.csdn.net/mrqiang9001/article/details/79520436 关于Mybatis的@Param注解   Mybatis 作为一个轻量级的数 ...

  7. 【mybatis】idea中 mybatis的mapper类去找对应的mapper.xml中的方法,使用插件mybatis-plugin

    idea中 mybatis的mapper类去找对应的mapper.xml中的方法,使用插件mybatis-plugin,名字可能叫Free mybatis-plugin 安装上之后,可能需要重启ide ...

  8. Mybatis Generator自动生成的mapper只有insert方法

    – Mybatis Generator 生成的mapper只有insert方法 – 首先检查generatorConfig.xml中table项中的属性 enableSelectByPrimaryKe ...

  9. Mybatis的mapper代理开发dao方法

    看完了之前的mybatis原始的dao开发方法是不是觉得有点笨重,甚至说没有发挥mybatis 作为一个框架的优势.总结了一下,原始的dao方法有以下几点不足之处 dao接口实现方法中存在大量的模板方 ...

随机推荐

  1. Spring,SpringMVC,MyBatis,Hibernate,Servlet的生命周期,jsp有哪些内置对象,Tomcat,Cookie和Session的作用以及区别,oracle,MYSQL等面试题总结

    1. 什么是Spring,谈谈你对Spring的理解 Spring是我们JAVA开发人员在搭建后台时选用的一个轻量级的开源框架,Spring框架目前也是功能丰富,十分优秀企业级采用最多的一个框架. S ...

  2. Ubuntu 16.04 sudo免密码visudo sudoers设置

    使用sudo visudo调用nano对 /etc/sudoers 进行修改 $ sudo visudo 在想修改的对象最后加上 NOPASSWD: ALL 注意:在后面的设置会覆盖前面的设置

  3. WKWebView 网络请求Header 丢失

    WKWebView 是苹果手机上主要的H5加载控件,它相比UIWebView 有诸多优势.在次不做比较,但是它的坑缺比较多.网上也有很多的例子但是做的比较好的真不多,我在这里推荐俩博客供大家参考.ht ...

  4. 【EFCore】利用Entityframework Core创建数据库模型

    利用Entityframework Core创建数据库模型 本文中Entityframework Core版本为v3.1.6 简介 Entity Framework (EF) Core 是微软轻量化. ...

  5. CopyOnWriteArrayList源码阅读笔记

    简介 ArrayList是开发中使用比较多的集合,它不是线程安全的,CopyOnWriteArrayList就是线程安全版本的ArrayList.CopyOnWriteArrayList同样是通过数组 ...

  6. JavaScript设计模式之策略模式【组合委托】

    前言:语言只是工具,思想才是核心 今天要总结的是 策略模式 策略在开发中的应用非常广泛,所以也是非常常见且使用的设计模式. 在实际开发中,往往在实现一个功能时,有多种解决方案可行. 常见场景: 解压: ...

  7. 输入url后的加载过程~

    1)查找域名对应的IP地址: 2)建立连接(TCP的三次握手): 3)构建网页: 4)断开连接(TCP的四次挥手): TCP的三次握手:为了准确无误的把数据送到目标处,TCP协议采用了三次握手策略,用 ...

  8. 数据结构与算法笔记(java)目录

    数据结构: 一个动态可视化数据结构的网站 线性结构 数组 动态数组 链表 单向链表 双向链表 单向循环链表 双向循环链表 栈 栈 队列 队列 双端队列 哈希表 树形结构 二叉树 二叉树 二叉搜索树 A ...

  9. cinder-volume服务上报自己的状态给cinder-scheduler的rpc通信代码分析

    以juno版本为基础,主要从消息的生产者-消费者模型及rpc client/server模型来分析cinder-volume是如何跟cinder-scheduler服务进行rpc通信的 1.cinde ...

  10. Java 8新特性(二):Stream API

    本篇文章继续介绍Java 8的另一个新特性--Stream API.新增的Stream API与InputStream和OutputStream是完全不同的概念,Stream API是对Java中集合 ...