Why MyBatis Mapper Methods Cannot Be Overloaded and How to Locate Their Corresponding SQL in XML
This article explains, from source‑code analysis, why MyBatis mapper methods cannot be overloaded, shows the resulting BeanCreationException, walks through the MyBatis‑SpringBoot auto‑configuration that builds SqlSessionFactory, and demonstrates how to trace a mapper method to the exact SQL statement defined in the XML mapping file.
When beginners start using MyBatis they often overload methods in a mapper interface, only to encounter runtime errors; this article clarifies why overloaded mapper methods are not allowed.
Environment : The examples are based on MyBatis 3.5 and SpringBoot 2.3.3.RELEASE .
Wrong Example – two selectList methods with different parameters are declared in the same mapper interface:
public interface UserMapper {
List
selectList(@Param("userIds") List
userIds);
List
selectList(Integer gender);
}Running the application produces a BeanCreationException because the generated MappedStatement IDs clash:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' ... Mapped Statements collection already contains value for cn.cb.demo.dao.UserMapper.selectList. please check file [...UserInfoMapper.xml] and file [...UserInfoMapper.xml]Why Overloading Fails
The SpringBoot MyBatis starter creates the SqlSessionFactory via MybatisAutoConfiguration . During factory creation the method xmlMapperBuilder.parse() parses each mapper XML and builds a MappedStatement for every <select> , <insert> , etc. The statement ID is generated as applyCurrentNamespace(id, false) , which resolves to fullMapperClassName + '.' + methodName . Because the ID must be unique, overloading two methods with the same name creates duplicate IDs.
The MappedStatement objects are stored in a StrictMap<MappedStatement> called mappedStatements . Its put(k, v) method throws an exception if the key (the ID) already exists, which is exactly what happens when a mapper method is overloaded.
protected final Map
mappedStatements = new StrictMap
("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource()); public void addMappedStatement(MappedStatement ms) {
// key is id
mappedStatements.put(ms.getId(), ms);
}How to Find the Corresponding SQL
When a mapper method is invoked, MyBatis looks up the MappedStatement by its ID in the configuration.getMappedStatement(statement) call inside DefaultSqlSession#selectList :
public List
selectList(String statement, Object parameter) {
MappedStatement ms = configuration.getMappedStatement(statement);
// ... execute the SQL defined by ms
}Thus the SQL is retrieved from the XML file whose id matches the fully‑qualified mapper method name.
Conclusion
The mapper method ID is constructed as MapperClassFullName + '.' + methodName ; because MyBatis stores statements in a map that disallows duplicate keys, overloading mapper methods leads to ID collisions and bean creation failures. To locate the SQL for a given method, follow the ID lookup in the MyBatis configuration.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.