栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

MyBatis内的Mapper接口方法为什么不能重载

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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 list);
}
2.2. Mapper.xml

注意当前的 namespace 为




    
        
        
        
        
    
    
        id
        , username, password, nickname
    

    
    
        insert into shiro_user (username, password, nickname) values
        
            (#{item.username},#{item.password},#{item.nickname})
        
    

	......

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 填充上 namespace
  	id = applyCurrentNamespace(id, false);
  	boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
  	// 2.使用参数构建 MappedStatement.Builder
  	MappedStatement.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 构建 MappedStatement
  	MappedStatement 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 是 ms
    mappedStatements.put(ms.getId(), ms);
}

// mappedStatements 是一个 StrictMap
protected final Map mappedStatements = new StrictMap("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 接口中有对应的同名方法,此时是不会发生错误的,当然这样就不是方法重载了

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/755866.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号