MyBatis: извините, я не могу нести этот горшок (урок для юных программистов)

Java
MyBatis: извините, я не могу нести этот горшок (урок для юных программистов)

Я Кайт, официальный аккаунт "Воздушный змей в древности", технический официальный аккаунт не только с технологиями, но и слэш-разработчик 6 лет, много лет в кружке программирования, в основном работающий на Java, а также на Python и реагировать. Серия статей Spring Cloud завершена, и вы можете перейти кмой гитхабПолную серию смотрите на . Вы также можете ответить на «pdf» в официальном аккаунте, чтобы получить мою тщательно созданную версию полного руководства в формате pdf.

Я пишу код уже много лет, и у меня всегда была привычка.Пока функциональные модули, которые нужно сделать, не очень сложные, я обычно прихожу и пишу кусок кода.После того, как функции будут выполнены, я запустите сервисный тест и измените его, если возникнут какие-либо проблемы (честно говоря, Unit-тестов много не пишут). Вместо того, чтобы тестировать его после написания интерфейса или метода, самая длинная запись должна состоять в том, чтобы писать код 4 или 5 дней подряд, а затем пройти тест.

Ватерлоо на Кодовой дороге

Однако буквально два дня назад я почувствовал, что столкнулся с Ватерлоо Code Life, на самом деле сталкивался с ним не раз, каждый раз, когда заканчиваю кататься, медленно встаю и забываю. На этот раз я записал это, чтобы не забыть.

Дело вот в чем, я два дня назад должен добавить функцию в проект. ORM проекта использует MyBatis.Поскольку таблица базы данных добавляется, слой DAO и файл отображения MyBatis (mapper.xml) должны быть сгенерированы соответственно. Поскольку я не знаком с предыдущим бизнесом, я просто построил все классы сущностей, бизнес-классы, файлы сопоставления, классы перечисления и т. д., а затем написал два простых интерфейса для отладки, поэтому я нажал кнопку «Пуск». , проект запускается нормально и выглядит так идеально.

Я построил запрос для тестирования только что написанного интерфейса, и когда запрос был отправлен, в консоли IDEA появилось знакомое исключение.invalid bound statement (not found), я боюсь, что студенты, которые использовали MyBatis, не знают этого исключения.Это означает, что когда мы вызываем метод DAO, соответствующий оператор не найден в файле mapper.xml, или не найден определенный вами блок SQL-запроса.

Это исключение может возникнуть по следующим причинам:

  1. Пространство имен XML-файла несовместимо с соответствующим именем интерфейса.
  2. Метод в классе интерфейса не соответствует идентификатору оператора в файле xml.
  3. В xml файле есть комментарии на китайском
  4. Не стесняйтесь добавить пробел или пустую строку в файл xml и сохранить его, это может решить проблему.

Если вы используете инструмент для автоматической генерации xml, это нормально.Если вы создаете его вручную, эта проблема, скорее всего, возникнет из-за халатности.Например, мы скопировали его из другого файла и забыли изменить пространство имен, или имя метода интерфейса и идентификатор оператора отличаются на одну букву или не соответствует алфавитному порядку. Это исключение очень хлопотное, например, если есть разница в одну букву, ее сложно найти, поэтому лучше написать имя метода интерфейса и скопировать в xml.

Хотя я какое-то время не прикасался к MyBatis, будучи старым драйвером, я совсем не паникую, когда сталкиваюсь с этой проблемой, потому что, хотя это файл xml, автоматически сгенерированный инструментом, я добавил несколько блоков операторов и идентификатор был также набран вручную, и сообщение об ошибке действительно было добавлено мной, поэтому я догадался, что имя должно быть неправильным, неправильная буква или порядок был несовместимым, поэтому я вошел и проверил, но я не найти какие-либо проблемы, просто на всякий случай я зашел в интерфейс и скопировал имя метода в xml, а затем убедился, что с пространством имен проблем нет, нет китайского комментария, и добавил пустую строку в xml (хотя этот метод еще ни разу не использовался для решения проблемы), а затем перезапустил элемент, однако исключение все равно не исчезает.

Выпрыгнуть вовремя, не застрять в нем

Это немного странно, еще раз проверил, да, все в норме, проблемы не вижу. **Когда будет определено, что проблемы нет, она выскочит наружу, и ее нужно рассматривать с других сторон или на более высоком уровне, иначе велика вероятность, что она в ней застрянет. **Расставьте ключевые точки, это правило, подытоженное многими уроками. Я могу быть уверен, что у вызываемого в настоящее время метода интерфейса и инструкции нет никаких проблем. Очень вероятно, что это другая проблема. Может быть, файл xml не был скомпилирован и упакован, поэтому я пошел в целевой каталог, чтобы проверить , там да, и глядя на содержимое, я уверен, что нет никаких проблем.

Иногда проблема очень странная, может быть связана с IDE, поэтому используюmvn cleanКоманда очистилась и снова запустилась, но проблема осталась.

Далее я попытался удалить этот xml и создать новый, но проблема осталась.

Выскакивайте еще раз, у вас нет проблем с этим методом?Тогда я создам новый метод,напишу самый простой SQL и сделаю имя метода немного проще,чтобы посмотреть не будет ли проблем.В итоге я нашел новый мир, этот новый метод также сообщил об этой ошибке. Тогда есть новое направление для исследования.Попробую методы в других интерфейсах.В итоге у нескольких методов под этим именем пакета у всех такая ошибка,а у методов под другими именами пакетов проблем нет,т.к. xml файлы разных функции размещены в разных пакетах, то есть по разным путям.

Тогда я знаю, что это проблема сканирования xml-файла, она должна быть настроена MyBatis.mapperLocationsЕсть проблема, может быть я или другие коллеги случайно набрали лишнюю букву или что-то в этом роде. Итак, я открыл файл конфигурации и посмотрел на него,

mybatis:
  mapperLocations: com/xxx/aaa/mapper/*.xml,com/xxx/aaa/bbb/mapper/*.xml,com/xxx/aaa/ccc/mapper/*.xml

Конфигурация MyBatismapperLocationsНастроены три пути пакетов, то есть найти из этих трех пакетов*.xmlПерейдите к анализу, но после проверки обнаруживается, что проблем нет, файл конфигурации не имеет записи отправки git, и настроенный путь пакета правильный, два других пакета сканируются нормально, то естьcom/xxx/aaa/ccc/mapper/*.xmlПроблема с этим пакетом. Итак, я попробовал следующие методы:

  1. Помещение этого проблемного пути к пакету первым не сработало.
  2. Поместите два других комментария, оставив только проблемный, который недействителен.
  3. Может ли быть так, что MyBatis читает конфигурацию где-то еще? Итак, я закомментировал эту конфигурацию, и оказалось, что была проблема, указывающая на то, что эта конфигурация была прочитана.

Исходный код хорош

На данный момент прошло много времени, и проблема становилась все более и более странной, но должна быть причина, и где-то должна быть проблема. Никак не могу найти проблему самого проекта, никак, могу только подозревать, что проблема с MyBatis, может действительно спровоцировал скрытый баг самого MyBatis.

Этот метод не используется, если только это не крайняя мера, то есть отладка исходного кода MyBatis. Если подумать, я все еще знаком с исходным кодом MyBatis. Тогда давай встретимся снова.

mybatis-spring-boot-starter имеет только три файла Java, из которыхMybatisAutoConfigurationявляется критически важным для бизнеса классом.

И мы знаем, что в MyBatisSqlSessionFactoryявляется очень важным объектом, поэтому мы добавляем точку останова вsqlSessionFactory(DataSource dataSource)на этом методе.

Если отлаживать исходный код фреймворка с открытым исходным кодом впервые, часто невозможно сразу найти позицию, по сути, это не имеет значения, вы можете попасть в точку останова в любой позиции, главное — дважды выполните его медленно.Процесс чтения исходного кода и отладки сам по себе является длительным процессом.

@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource);
   // 省略...
    if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
      factory.setMapperLocations(this.properties.resolveMapperLocations());
    }
    return factory.getObject();
}

В приведенном выше коде я оставляю только код, связанный с этой проблемой, то есть процесс разбора mapperLocations, который является кодом в приведенном выше коде.this.properties.resolveMapperLocations()Сюда.

public Resource[] resolveMapperLocations() {
    ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
    List<Resource> resources = new ArrayList<Resource>();
    if (this.mapperLocations != null) {
      for (String mapperLocation : this.mapperLocations) {
        try {
          Resource[] mappers = resourceResolver.getResources(mapperLocation);
          resources.addAll(Arrays.asList(mappers));
        } catch (IOException e) {
          // ignore
        }
      }
    }
    return resources.toArray(new Resource[resources.size()]);
}

Когда я продолжил отслеживать код, я обнаружил, что MyBatis действительно распознал три пути к пакетам в файле конфигурации,this.mapperLocationsЭто набор массивов из этих трех путей к пакетам.

Затем спуститесь по методуresourceResolver.getResources(mapperLocation)Проанализируйте каждый путь и обнаружите, что первые два пакета возвращаются нормально.Resource[], то есть соответствующий ресурс файла xml, а последний возвращенный действительно пустой массив, причина проблемы очень близка.

Затем снова запустите отладку, когда будет разрешен последний путь пакета, введитеresourceResolver.getResources(mapperLocation)Внутри метода посмотрите, что происходит внутри, и, наконец, обнаружите, что после вызова следующего кода возвращаемый rootDirURL представляет собой абсолютный путь, то есть физический путь, по которому находится xml.

URL rootDirURL = rootDirResource.getURL();

На этот раз я, наконец, нашел проблему.Этот абсолютный путь-это не путь, где находится xml, а путь под другим подмодулем.После сравнения обнаруживается, что,Оказалось, что в подмодуле была создана новая папка с таким же именем, в результате чего получилось два одинаковых пути к пакетам, а приведенный выше код вернул абсолютный путь к другому пакету.. Итак, я связался со своими коллегами и спросил, почему этот пакет был создан.Я обнаружил, что он был недавно добавлен, но заброшен и бесполезен, поэтому я удалил его и решил проблему.

Этой проблемы следует избегать при нормальной разработке проекта.Модули и модули не должны иметь одинаковое имя пакета и должны следовать следующему именованию:

Модуль А: com.kite.moduleA

МодульB: com.kite.moduleB

Это в корне решает проблему и предотвращает ненужные неприятности.

Наконец

Это исключение MyBatis действительно вызывает головную боль, потому что причина ошибки не очевидна и т. Д., Все проблемы, вызванные файлом xml, не так просто устранить, большинство случаев вызваны человеческая небрежность, а ошибки как правило, более скрыты.

Когда проблема не может быть найдена и решена после многократных проверок, часто необходимо изменить образ мышления, вовремя выскочить и пересмотреть проблему под другим углом или на более высоком уровне и, возможно, найти причину проблемы. Быстрее.

При использовании фреймворка с открытым исходным кодом, если возникла проблема и вы долго не можете найти решение, можно попробовать отладить исходный код, что не так сложно, как вы думаете.

Не жди сильного мужика, сначала поставь лайк, меня вечно трахают зря, и мое тело этого не выдерживает!

Я Kite, паблик-аккаунт «Kite in Ancient Times», слэш-разработчик, много лет в кружке программирования, в основном работаю на Java, а также очень хорошо играю на Python и React. Вы можете добавить меня в друзья в официальном аккаунте, вступить в группу для общения и обучения, так же в группе много одноклассников с крупных заводов.