MyBatis内的Mapper接口方法为什么不能重载
目录
- 1.前言
- 2.测试案例
- 2.1. `Mapper` 接口
- 2.2. `Mapper.xml`
- 3.`Mapper.xml` 文件的解析
- 3.1.`parseStatementNode()`
- 3.2.`addMappedStatement()`
- 3.3.`addMappedStatement()`
- 4.总结
1.前言
今天在翻阅有关 MyBatis
专题的知识点时,看到了这样一道面试题:MyBatis
内的 Mapper
接口方法为什么不能重载,对于这个问题,幸好前几天查漏补缺了一下 MyBatis
专题,毋庸置疑它考的是你对 MyBatis
源码的熟悉程度,少说多做看源码
2.测试案例
2.1. Mapper
接口
package org.example.dao;@Mapper
public interface UserMapper {int deleteByPrimaryKey(Integer id);int insert(User record);int insertSelective(User record);User selectByPrimaryKey(Integer id);int updateByPrimaryKeySelective(User record);int updateByPrimaryKey(User record);int batchAddUser(List<User> list);
}
2.2. Mapper.xml
注意当前的 namespace
为 <mapper namespace="org.example.dao.UserMapper">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.dao.UserMapper"><resultMap id="BaseResultMap" type="org.example.pojo.User"><id column="id" jdbcType="INTEGER" property="id"/><result column="username" jdbcType="VARCHAR" property="username"/><result column="password" jdbcType="VARCHAR" property="password"/><result column="nickname" jdbcType="VARCHAR" property="nickname"/></resultMap><sql id="Base_Column_List">id, username, password, nickname</sql><!--foreach批量插入--><insert id="batchAddUser" parameterType="java.util.List">insert into shiro_user (username, password, nickname) values<foreach collection="list" item="item" index="index" separator=",">(#{item.username},#{item.password},#{item.nickname})</foreach></insert>......
</mapper>
3.Mapper.xml
文件的解析
要知道 Mapper
接口方法为什么不能重载,首先就要知道 Mapper
接口和 Mapper.xml
文件在何时被解析的,鉴于文章篇幅的原因,本文只说重点源码,详细源码 在这里
3.1.parseStatementNode()
我们首先看 XMLStatementBuilder
类中的 parseStatementNode()
方法,也就是 这篇文章 的 2.5
节点的 parseStatementNode()
,如下
public void parseStatementNode() {String id = context.getStringAttribute("id");String databaseId = context.getStringAttribute("databaseId");if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {return;}// 省略......builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);}
3.2.addMappedStatement()
MapperBuilderAssistant
类中的 addMappedStatement()
方法
public MappedStatement addMappedStatement(String id,SqlSource sqlSource,StatementType statementType,SqlCommandType sqlCommandType,Integer fetchSize,Integer timeout,String parameterMap,Class<?> parameterType,String resultMap,Class<?> resultType,ResultSetType resultSetType,boolean flushCache,boolean useCache,boolean resultOrdered,KeyGenerator keyGenerator,String keyProperty,String keyColumn,String databaseId,LanguageDriver lang,String resultSets) {if (unresolvedCacheRef) {throw new IncompleteElementException("Cache-ref not yet resolved");}// 1.给 id 填充上 namespaceid = applyCurrentNamespace(id, false);boolean isSelect = sqlCommandType == SqlCommandType.SELECT;// 2.使用参数构建 MappedStatement.BuilderMappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType).resource(resource).fetchSize(fetchSize).timeout(timeout).statementType(statementType).keyGenerator(keyGenerator).keyProperty(keyProperty).keyColumn(keyColumn).databaseId(databaseId).lang(lang).resultOrdered(resultOrdered).resultSets(resultSets).resultMaps(getStatementResultMaps(resultMap, resultType, id)).resultSetType(resultSetType).flushCacheRequired(valueOrDefault(flushCache, !isSelect)).useCache(valueOrDefault(useCache, isSelect)).cache(currentCache);ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);if (statementParameterMap != null) {statementBuilder.parameterMap(statementParameterMap);}// 3.使用 MappedStatement.Builder 构建 MappedStatementMappedStatement statement = statementBuilder.build();// 4.将 MappedStatement 添加到缓存configuration.addMappedStatement(statement);return statement;
}
id = applyCurrentNamespace(id, false)
:给这个段打上断点,Debug
运行看它填充的是什么namespace
我们 Step Over
一下,再看 id
结果,显然是给原来的方法名加上了全限类名
applyCurrentNamespace()
源码如下
3.3.addMappedStatement()
跟进 addMappedStatement()
方法,来到了 Configuration
类中的 addMappedStatement()
方法,源码如下
public void addMappedStatement(MappedStatement ms) {// StrictMap 的 put() 方法,key 是 id,value 是 msmappedStatements.put(ms.getId(), ms);
}// mappedStatements 是一个 StrictMap
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
StrictMap
的put()
方法,key = ms.getId()
,value = ms
。这个StrictMap
不允许有重复的key
,而存入的key
就是statement
中的id
。因此Mapper
接口中的方法不能重载
statement
中的id
值如下
4.总结
- 在同一个
namespace
中写了多个相同的id
映射,且在Mapper
接口中有对应的重载方法,由于MyBatis
在构建MappedStatement
缓存时,是通过当前的namespace + 方法名
作为key
添加进StrictMap
缓存的,此时就出现了key
的不唯一性,导致出错 - 同理,在不同的
namespace
中写了多个相同的id
映射,且在不同的Mapper
接口中有对应的同名方法,此时是不会发生错误的,当然这样就不是方法重载了
MyBatis内的Mapper接口方法为什么不能重载相关推荐
- mybatis如何根据mapper接口生成其实现类
SpringBoot集成mybatis mybatis的statement的解析与加载 mybatis如何根据mapper接口生成其实现类 mybatis的mapper返回map结果集 mybatis ...
- Spring整合MyBatis原理之Mapper接口和xml文件的解析
目录 1. 前言 2. 类 `SqlSessionFactoryBean` 2.1. 实现了 `FactoryBean` 接口的 `getObject()` 2.2. `buildSqlSession ...
- 解决spring mybatis 整合后mapper接口注入失败
spring整合mybatis,在dao层我们只写一个接口,配置相应的*mapper.xml文件, 报如下错误: 1 org.springframework.beans.factory.Unsatis ...
- Mybatis中mapper接口里方法重载的实现
看了网上的很多文章,说mapper接口里不能写重载方法,感觉这种说法不对,mapper接口是可以实现重载方法的. 实现方法 例如: package mapper;import pojo.User;im ...
- mybatis接口中的方法重载_MyBatis的Mapper接口以及Example的实例函数及详解
一.mapper接口中的方法解析 mapper接口中的函数及方法 方法 功能说明 int countByExample(UserExample example) thorws SQLException ...
- 一个mapper接口有多个mapper.xml 文件_MyBatis 源码解析:映射文件的加载与解析(上)
上一篇我们分析了配置文件的加载与解析过程,本文将继续对映射文件的加载与解析实现进行分析.MyBatis 的映射文件用于配置 SQL 语句.二级缓存,以及结果集映射等,是区别于其它 ORM 框架的主要特 ...
- Mapper 接口无法注入或Invalid bound statement (not found)
我们在使用MyBatis 的时候可能会遇到Mapper 接口无法注入,或者mapperstatement id 跟Mapper 接口方法无法绑定的情况.基于绑定的要求或者说规范,我们可以从这些地方去检 ...
- Mybatis-Dao层开发之Mapper接口
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法. Mapper接口开发 ...
- mapper接口原理
mapper的实现原理是动态代理 那什么是动态代理呢?动态代理就是在程序运行期间由jvm通过反射等机制动态生成的,所以不会存在代理类的字节码文件,故我们在mybatis中使用mapper接口的时候没有 ...
- Mybatis接口Mapper内的方法为啥不能重载?
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 来源:https://my.oschina.net/zud ...
最新文章
- html流动模型,javascript的事件流模型都有什么?
- 【c语言】蓝桥杯算法训练 薪水计算
- 让AI个性化而且功耗更低 IBM研发新型神经网络芯片
- pca主成分分析结果解释_SKLEARN中的PCA(Principal Component Analysis)主成分分析法
- mysql force index报错_新特性解读 | MySQL 8.0 索引特性4-不可见索引
- mysql 字段操作_Mysql:数据库操作、数据表操作、字段操作整理
- 谷歌浏览器F12快速定位网页上组件信息
- 【论文+推导】Predictability and Prediction of Human Mobility Based on Application-Collected Location Data
- 检验杜宾 瓦森检验法R语言_2018年9-11月高级计量经济学主要授课内容概要
- jmeter+ant+jenkins接口自动化测试框架
- 上海公交投诉电话:12319
- 解决git push报错问题
- 【读万卷书】《挪威的森林》
- Web 开发最有用的50款 jQuery 插件集锦——《图片特效篇》
- BACnet/IP网关如何采集楼宇集中控制系统数据
- Kubernetes Pod 网络精髓:pause 容器详解
- 82岁高龄的高德纳仍在写《计算机程序设计艺术》,那是他未完成的人生目标...
- JS中 new FormData() - FormData对象的作用及用法
- String类-统计子串在字符串中出现的次数
- 神经网络Python实现(9行代码)
热门文章
- 容器技术Docker K8s 30 容器服务ACK基础与进阶-弹性伸缩
- The Basic Knowledge of Graph(图的基本知识)
- sizeof计算结构体时的内存对齐问题
- 归类问题:简单的代价函数和梯度下降----吴恩达机器学习
- 译林 五年级上 单词_译林版小学英语五上Unit 4 HobbiesStory time公开课优质课件教案视频教案...
- antd vue form 手动校验_vue测试模板与jsonSchema自动生成elment组件
- 【生信进阶练习1000days】day10-vcf format
- python 学习小结(1)
- android加载图片+背景,Android开发中ImageLoder加载网络图片时将图片设置为ImageView背景的方法...
- (博主可帮找错)Servlet.service() for servlet [dispatcherServlet] path [] threw exception feign.Feig,可截图私聊博主