mybatis接口中的方法重载_从源码角度分析为什么MyBatis的Mapper接口方法不能重载...

1:我们从MyBatis配置开始解析

解析入口在 SqlSessionFactoryBean.class中,至于为什么,大家可以查看 juejin.cn/post/689673… 这篇文文章,里面解析了SpringBoot+MyBatis的整合源码解析

2:开始解析

public void parse() {

//判断该配置文件(编写Sql的xml文件)是否已经被解析过,解析过的配置文件会被放到Set集合当中

if (!configuration.isResourceLoaded(resource)) {

//开始解析(编写Sql的xml文件)mapper节点,我们进入configurationElement方法

configurationElement(parser.evalNode("/mapper"));

configuration.addLoadedResource(resource);

bindMapperForNamespace();

}

parsePendingResultMaps();

parsePendingCacheRefs();

parsePendingStatements();

}

复制代码

3:进入configurationElement方法

//这里就开始解析mapper节点下的各种属性信息了,我们重点看下解析select|insert|update|delete等元素信息

private void configurationElement(XNode context) {

try {

String namespace = context.getStringAttribute("namespace");

if (namespace == null || namespace.isEmpty()) {

throw new BuilderException("Mapper's namespace cannot be empty");

}

builderAssistant.setCurrentNamespace(namespace);

cacheRefElement(context.evalNode("cache-ref"));

cacheElement(context.evalNode("cache"));

parameterMapElement(context.evalNodes("/mapper/parameterMap"));

resultMapElements(context.evalNodes("/mapper/resultMap"));

sqlElement(context.evalNodes("/mapper/sql"));

//我们重点解析下面这个方法

buildStatementFromContext(context.evalNodes("select|insert|update|delete"));

} catch (Exception e) {

throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);

}

}

复制代码

4:进入buildStatementFromContext()方法

private void buildStatementFromContext(List list) {

if (configuration.getDatabaseId() != null) {

buildStatementFromContext(list, configuration.getDatabaseId());

}

buildStatementFromContext(list, null);

}

复制代码

5:继续进入下面buildStatementFromContext(list, null);

private void buildStatementFromContext(List list, String requiredDatabaseId) {

for (XNode context : list) {

final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);

try {

//进入这个方法

statementParser.parseStatementNode();

} catch (IncompleteElementException e) {

configuration.addIncompleteStatement(statementParser);

}

}

}

复制代码

6:进入statementParser.parseStatementNode();

public void parseStatementNode() {

/**

* 中间省略很多代码,但是重点是下面这行代码

*/

builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,

fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,

resultSetTypeEnum, flushCache, useCache, resultOrdered,

keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);

}

复制代码

7:我们继续跟进builderAssistant.addMappedStatement方法

//这里我截取了一段代码,重点是MapperStatement这个对象,可以说我们执行一条Sql语句的相关信息都在这个对象里面了

ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);

if (statementParameterMap != null) {

statementBuilder.parameterMap(statementParameterMap);

}

MappedStatement statement = statementBuilder.build();

configuration.addMappedStatement(statement);

复制代码

8:查看MapperStatement对象

343e5601ec43ddbbb0373a7db5a3f6dd.png

MapperStatement有几个很重要的属性

id: 在我们执行Mapper接口一个方法的时候,需要依靠这个id找到对应的MapperStatement对象,然后拿到其中的Sql语句

SqlSource:这里面就封装了我们在xml配置文件中编写的SQL语句,大家在图中就可以看到了

9: MapperStatement对象总结

现在可以对MapperStatement做个总结了:MyBatis在解析我们编写的xml配置的时候,当我们解析一条Sql语句的时候,那么就会把对应的id,sql语句都封装到MapperStatement这个对象中

10:MapperStatement中id的组成

3cc055d463405d1410c12484d5edbfb7.png

id = namespace + id

所以我们在执行Mapper接口的时候,会通过Mapper接口的 全路径名+方法名组成的id去寻找对应的MapperStatement对象,就是通过对比id来进行比较的

11:现在继续第7步

在生成了MapperStatement对象之后,MyBatis会把这个对象存储到一个Map中,而key值就是MapperStatement对象中的id

12:总结

所以如果我们在Mapper接口中有同样名称的方法,那么在生成MapperStatement对象的时候,id就会重复,也就意味着之前存储的MapperStatement对象就会被覆盖掉

map.put("com.coco.mapper.UserDao.query",MapperStatement1);

map.put("com.coco.mapper.UserDao.query",MapperStatement2);

那么MapperStatement1就会被覆盖掉,那么会出现什么问题呢?

比如Mapper接口方法如下

User query(Integer id);

所对应的sql = select * from user where id = #{id}

User query(String name);

所对应的sql = select * from user where name = #{name}

因为先解析的MapperStatement对象被后面的覆盖掉了,比如MyBatis先解析了第一个方法,然后再解析第二个方法,那么第一个方法被覆盖掉了,当我们执行第一个方法的时候,通过id就会找到第二个方法的MapperStatement对象了,那么Sql语句就错了

13:结束语

现在大家能理解为什么Mapper接口方法不能重载的原理了嘛

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值