preface
- In the introduction to the early
Mybatis
I may have made a mistake when I was writingMapper
Interface overload of the method, but always run up the error, at that time is really very depressed, but they can not find out the reason, can only silently change the method name, ha ha, how humble operation. - Today I will write an article from the source point of view for you to answer the question why
Mybatis
Cannot overload methods in?
Environment configuration
- Everything in this article is based on
Mybatis3.5
andSpringBoot - 2.3.3. RELEASE
.
Error model
- For example, if you have two requirements, one is to filter users by their ID, the other is to filter users by their gender, then the Mapper overload method is as follows:
public interface UserMapper {
List<UserInfo> selectList(@Param("userIds") List<String> userIds);
List<UserInfo> selectList(Integer gender);
}
Copy the code
- There is nothing wrong with this, but starting the project, the following error is reported:
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(AbstractAutow ireCapableBeanFactory.java:1336)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableB eanFactory.java:1176)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFac tory.java:556) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFacto ry.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(AbstractAutowireCapableBeanF actory.java:1509) .81 more Copy the code
-
What does that mean? Meng made the ~
-
General meaning: cn. Cb. Demo. Dao. UserMapper. The selectList this id already exist, leading to failed to create sqlSessionFactory.
Why can’t I reload?
- You can see the above exception prompt to know the creation
sqlSessionFactory
Failed, this must be no stranger to it, as the name implies, is to createSqlSession
In the factory. - Springboot and Mybatis will have an automatic configuration class for the launcher
MybatisAutoConfiguration
, one of the pieces of code is createsqlSessionFactory
, as shown below: - Create failed; create failed; create failed;
❝
XML file and Mapper interface, Mapper method and XML file < SELECT >, < INSERT > tags one by one, so how Mapper method and XML < SELECT > tags corresponding, of course, is a unique ID corresponding. What is the value of this ID and how does it correspond? Here are the explanations.
❞
- As above,
SqlSessionFactory
The previous part of the code was all about setting up the configuration, not parsing the XML, so the answer is definitely in the last linereturn factory.getObject();
“, so here is the break point, bit by bit. So all the way toorg.mybatis.spring.SqlSessionFactoryBean#buildSqlSessionFactory
In this method, one of the pieces of code looks like this: - Here,
xmlMapperBuilder.parse();
Parsing XML files with the Mapper interface, keep going. - Skip the unimportant code, in
org.apache.ibatis.builder.xml.XMLMapperBuilder#configurationElement
There is an important line of code in this method, as shown below: - This is based on the XML file
select|insert|update|delete
These tags start buildingMappedStatement
. Keep following. - Skip the unimportant code and see that
org.apache.ibatis.builder.MapperBuilderAssistant#addMappedStatement
The return value of this method is zeroMappedStatement
Needless to say, this must be the method, a closer look, clearly see the buildid
Code, as shown below: - As you can see from the figure above, create
id
The code forid = applyCurrentNamespace(id, false);
, the specific implementation is shown in the figure below:
❝
The code above is clear: id in MappedStatement =Mapper’s full class name +’.’+ method name. If you reload, there must be an MappedStatement with the same ID.
❞
- That doesn’t mean you can’t overload a method, just repeat it, there’s no conflict. Here’s a structure to look at:
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
Copy the code
- To build a good
MappedStatement
Will be deposited in themappedStatements
, the following code:
public void addMappedStatement(MappedStatement ms) {
/ / key is id
mappedStatements.put(ms.getId(), ms);
}
Copy the code
StrictMap
theput(k,v)
The method is shown below:
❝
This should make sense, because the exception that was thrown now corresponds to the exception message above. StrictMap does not allow duplicate keys, and the stored keys are ids. Therefore, methods in Mapper cannot be overloaded.
❞
How do I find the corresponding SQL in XML?
- When using Mybatis, simply call the method in Mapper to execute SQL, as follows:
List<UserInfo> userInfos = userMapper.selectList(Arrays.asList("192"."198"));
Copy the code
❝
How do you find the CORRESPONDING SQL for a simple one-line call? Map
,>
mappedStatements by id.
❞
- in
org.apache.ibatis.session.defaults.DefaultSqlSession#selectList
The method has this line of code as shown below: MappedStatement ms = configuration.getMappedStatement(statement);
This line of code is based onid
frommappedStatements
Get the correspondingMappedStatement
, the source code is as follows:
public MappedStatement getMappedStatement(String id) {
return this.getMappedStatement(id, true);
}
Copy the code
conclusion
- At this point in the article, it’s pretty clear why methods in Mapper can’t be overridden, but it’s all about this and this, right
Id = full class name of Mapper +'.'+ method name
. - If you think the author wrote a good, harvest, little attention, share a wave, pay attention to the wechat public number
Code ape technology column
First hand article push!!