Почему методы в Mapper Mybatis не могут быть перегружены?

Java

предисловие

  • НачинаяMybatisВозможно вы ошиблись при написанииMapperЯ перегружала методы в интерфейсе, но он всегда сообщал об ошибке при запуске.Это было действительно удручающе в то время, но я не мог выяснить причину, поэтому я мог только молча изменить имя метода, ха-ха, что за скромная операция.
  • Сегодня я напишу статью, чтобы объяснить почему с точки зрения исходного кода.MybatisМетод не может быть перегружен?

Конфигурация среды

  • Все в этой статье основано наMybatis3.5а такжеSpringBoot-2.3.3.RELEASE.

Демонстрация ошибок

  • Например: предположим, что сейчас есть два требования: одно — фильтровать пользователей по идентификатору пользователя, а другое — фильтровать по полу пользователя.В настоящее время перегруженный метод в Mapper выглядит следующим образом:
public interface UserMapper {
    List<UserInfo> selectList(@Param("userIds") List<String> userIds);

    List<UserInfo> selectList(Integer gender);
    }
  • В этом нет ничего плохого, но когда я запускаю проект, сообщается следующая ошибка:
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(AbstractAutowireCapableBeanFactory.java:1336)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1176)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.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(AbstractAutowireCapableBeanFactory.java:1509)
 ... 81 more
  • Что вы имеете в виду под так много? ошеломлен~

  • примерно означает:cn.cb.demo.dao.UserMapper.selectListэтоidуже существует, что привело к созданиюsqlSessionFactoryПотерпеть неудачу.

Почему нельзя перегружать?

  • Из приведенного выше запроса об исключении вы можете узнать, что созданиеsqlSessionFactoryНе удалось, это должно быть не понаслышке, как следует из названия, это создатьSqlSessionфабрика.
  • Springboot и Mybatis будут иметь начальный класс автоконфигурации.MybatisAutoConfiguration, в котором есть фрагмент кода, создающийsqlSessionFactory,Как показано ниже:
  • Поскольку создание не удалось, здесь должно быть исключение, здесь"Главная идея"это:

РазобратьXMLдокументы иMapperИнтерфейс, который объединяет методы Mapper с файлом XML.<select>,<insert>Если между тегами существует однозначное соответствие, как методы в Mapper соответствуют методам в XML?<select>Эти теги соответствуют, конечно же, уникальныidСоответственно, как именноidКаково значение , и как оно соответствует? Объясните один за другим ниже.

  • как на фото вышеSqlSessionFactoryВ процессе создания предыдущая часть кода предназначена для установки некоторой конфигурации и не включает разбор содержимого XML, поэтому ответ должен быть в последней строке.return factory.getObject();, поэтому поставьте здесь точку останова и немного понаблюдайте. Так что покаorg.mybatis.spring.SqlSessionFactoryBean#buildSqlSessionFactoryВ этом методе фрагмент кода выглядит следующим образом:
  • здесьxmlMapperBuilder.parse();Это для анализа XML-файла и интерфейса Mapper и продолжения поиска.
  • Пропустить неважный код, вorg.apache.ibatis.builder.xml.XMLMapperBuilder#configurationElementВ этом методе есть важная строка кода, как показано ниже:
  • Вот согласно файлу XMLselect|insert|update|deleteЭти теги начинают строитьсяMappedStatement. Продолжайте следить, чтобы увидеть.
  • Пропустите неважный код, посмотрите на этот разorg.apache.ibatis.builder.MapperBuilderAssistant#addMappedStatementВозвращаемое значение этого метода равноMappedStatement,Излишне говорить, что это должен быть этот метод.Если присмотреться, то хорошо видно построениеidкод, как показано ниже:
  • Как видно из рисунка выше, создайтеidКодid = applyCurrentNamespace(id, false);, конкретная реализация выглядит следующим образом:

Код на картинке выше уже очень ясен,MappedStatementсерединаid=Mapper的全类名+'.'+方法名. Если он перегружен, он обязательно будет существоватьidидентичныйMappedStatement.

  • На данный момент это на самом деле не означает, что метод не может быть перегружен, повторяйте, повторяйте, и конфликта нет. Здесь нам нужно посмотреть на структуру следующим образом:
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
      .conflictMessageProducer((savedValue, targetValue) ->
          ". please check " + savedValue.getResource() + " and " + targetValue.getResource());
  • построенMappedStatementбудет депонированmappedStatements, следующий код:
public void addMappedStatement(MappedStatement ms) {
    //key 是id 
    mappedStatements.put(ms.getId(), ms);
  }
  • StrictMapизput(k,v)Метод заключается в следующем:

Здесь следует понимать, исключение, выброшенное здесь, такое же, как и выше异常信息Сопоставьте это. этоStrictMapДубликаты не допускаютсяkey, в то время как сохраняетсяkeyто естьid. Поэтому методы в Mapper нельзя перегружать.

Как найти соответствующий SQL в XML?

  • При использовании Mybatis вы можете выполнить SQL, просто вызвав метод в Mapper следующим образом:
List<UserInfo> userInfos = userMapper.selectList(Arrays.asList("192","198"));

Как одна строка простых вызовов находит соответствующий SQL? На самом деле, согласноidотMap<String, MappedStatement> mappedStatementsнайти соответствующийMappedStatement.

  • существуетorg.apache.ibatis.session.defaults.DefaultSqlSession#selectListМетод имеет эту строку кода, как показано ниже:
  • MappedStatement ms = configuration.getMappedStatement(statement);Эта строка кода основана наidотmappedStatementsполучить соответствующийMappedStatement, исходный код выглядит следующим образом:
public MappedStatement getMappedStatement(String id) {
    return this.getMappedStatement(id, true);
  }

Суммировать

  • При написании статьи должно быть понятно, почему методы в Mapper нельзя перегружать, в конечном счете именно из-за этого и этогоid=Mapper的全类名+'.'+方法名.
  • Если вы считаете, что автор написал хорошо и что-то понял, пожалуйста, обратите внимание, поделитесь волной и обратите внимание на публичный аккаунт WeChat.码猿技术专栏Толчок статьи из первых рук! ! !