Очень доволен, наступил на яму в процессе использования mybatis

Java

В самом процессе разработки я наступил на яму mybatis, и я думаю, что это стоит записать и поделиться.

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

Подробности следующие: OgnlOps.equal(0,"") в mybatis возвращает true.

Во-первых, возвращение к истине здесь противоречит нашему здравому смыслу, а во-вторых, возвращение к истине, какие проблемы это принесет?

После прочтения этой статьи вы поймете.

В этой статье мы проанализируем эту проблему, отслеживая исходный код в соответствии с идеями написания возникающих проблем --> анализ проблем --> решение проблем.

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

Исходный код этой статьи: версия mybatis 3.5.3.

Предыстория, анализ спроса

Сначала установите фон и смоделируйте требование.

Есть таблица заказов, структура таблицы следующая:

Для упрощения задачи предположим, что в таблице всего две части данных:

Статус заказа номер заказа 1234 0【Закрыть】

Статус заказа с номером заказа 4321: 1【Открыт】

Разработана функция запроса имени заказа нечетким способом Интерфейс выглядит следующим образом:

Соответствующий ему mapper.xml написан так, и функция нормальная:

Теперь вам нужно добавить к существующей функции функцию фильтрации заказов по статусу:

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

Когда пользователь выбирает [] было оплачено, полученным фоном является номер 1, тип получения байтов.

Когда пользователь выбирает [Бесплатно], полученным фоном является число 0, которое принимается в байтовом формате.

готов развиваться

Теперь, когда требования определены, выполните фильтрацию по статусу заказа.

Все очень просто.Самая важная модификация это модификация mapper.xml.Что касается того,как передать его из фронтенда в xml,я не буду подробно объяснять.Думаю,что знакомые,пользовавшиеся mybatis,знают это.

Сначала добавьте в интерфейс входной параметр orderName:

Затем преобразуйте соответствующий xml

Точка преобразования очень проста: в xml-файле нажмите ctrl+c на исходный тег if, а затем ctrl+v, чтобы изменить имя внутри.

Начать самопроверку и столкнуться с проблемами

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

Модульный тест выглядит следующим образом: пройти в состояниях 0 и 1 соответственно

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

Запустим его, посмотрим на результаты выполнения:

статус = 0, количество запрошенных элементов = 2

статус = 1, количество запрошенных элементов = 1

Этот результат не тот, что мы ожидали! какова ситуация?

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

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

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

анализировать проблему

Первым шагом анализа на самом деле очень легко подумать. Мы впервые распечатаем SQL, чтобы увидеть, что является окончательным выполненным SQL, и тогда мы узнаем, почему возвращенный результат не соответствует ожиданию.

Итак, мы добавляем эту строку конфигурации в application.properties: logging.level.com.xxxx.xxxx.mapper=отладка Примечание. Замените указанный выше xxxx на путь к вашему собственному пакету картографа.

После добавления sql-печати мы обнаружили, что когда статус равен 0, mybatis не соединил для нас ключевое слово where.

Здесь естественно подумать о следующем шаге: почему mybatis не соединит для нас ключевое слово where?

Или еще вопрос: куда mybatis сплайсирует sql по какой логике?

Обычный метод заключается в добавлении точек останова для отслеживания, но я хотел бы поделиться «дерзкой» операцией, которую я проверил в свое время, и с ее помощью очень быстро найти проблему. Это обратная проверка.

обратный чек

Теперь мы определили, что это проблема склейки sql.Я также получил полный sql через лог.

Конфигурация лога такая: logging.pattern.console=%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level[%thread]%C{56}.%method:%L -%msg%n Распечатанный лог такой (часть его перехвачена):

В строке 143 файла org.apache.ibatis.logging.jdbc.BaseJdbcLogger журнал печатается в методе отладки Эта строка журнала — мой прорыв.

В этом месте я получил весь sql.Если я вернусь, я могу быстро найти, где генерируется sql.

Затем я устанавливаю точку останова в строке 143 BaseJdbcLogger и запускаю ее.

Через режим отладки idea мы можем получить всю цепочку вызовов от начала программы до точки останова. (Если изображение ниже нечеткое, вы можете нажать, чтобы просмотреть увеличенное изображение):

По цепочке вызовов, возвращаясь на три шага назад, мы видим, что sql получается изboundSql:

Так что из этого получилосьboundSql? Мы продолжаем возвращаться.

Возвращаясь на 11 шагов назад, мы можем увидеть процесс приобретенияboundSql:

Чтобы облегчить вам поиск исходного кода, я поместил здесь соответствующее имя метода: .ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)

Помните вопрос, с которого мы начали, мы не знаем, где и по какой логике склеен sql.

И это ответ на предыдущую часть. SQL создается 81 строкой кода org.apache.ibatis.executor.CachingExecutor: BoundSqlboundSql = ms.getBoundSql(parameterObject);

Итак, далее нам нужно всего лишь поставить точку останова перед этой строкой кода, и мы сможем узнать ответ на вторую половину вопроса: какая логика используется для ее конкатенации?

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

исходный код ключа

Ниже приведен обычный процесс прямого поиска, и, наконец, вы найдете наиболее важную часть полного текста: org.apache.ibatis.ognl.ASTNotEq#getValueBody

Почему число 0 и пустая строка "" возвращают true в mybatis? В исходном коде нет секрета, продолжайте отладку, и вы найдете это место: org.apache.ibatis.ognl.OgnlOps#doubleValue

Вернувшись сюда, настоящее сравнение здесь:

И v1, и v2 в конечном итоге стали 0.0. Таким образом, он возвращает истину.

Поскольку OgnlOps.equal(0,"") возвращает true, все выражение [OgnlOps.equal(0,"") ? Boolean.FALSE : Boolean.TRUE] возвращает FALSE.

Далее вам нужно ответить на эти три вопроса:

Откуда v1=0?

Откуда v2=""?

Что не так с возвратом FALSE?

Место, отмеченное цифрой 1 на рисунке, — это значение v1, а этот 0 — условие запроса, которое я передал.

Место, помеченное цифрой 2 на рисунке, является значением v2.Источником этого "" является выражение, которое я написал в теге if в файле mapper.xml.

Место, отмеченное цифрой три на рисунке, является ложным из-за этого выражения [OgnlOps.equal(0,"") ? Boolean.FALSE : Boolean.TRUE] возвращает false. Если возврат неверен, следующий код не будет введен:contents.apply(context).

И эта строка кода должна ответить на вторую половину нашего предыдущего вопроса, какую логику использует mybatis для сплайсинга sql?

Это анализ тестового условия в теге if, который мы написали в mapper.xml.Если условие выполнено, оно возвращает true, а содержимое в условии склеивается, то есть sql.

Поскольку тег if здесь выглядит следующим образом:

Где orderStatus!=null возвращает true, orderStatus !='' возвращает false, поэтому все выражение возвращает false, и sql в этом теге if не склеен.

До сих пор мы объединили исходный код, чтобы проанализировать, почему возникает проблема.

Решать проблему

Фактически, после анализа проблемы решение готово, нам нужно только изменить тег if в файле mapper.xml на это:

Или изменить его на это:

Посмотрите на результат выполнения:

Это соответствует нашим ожидаемым результатам.

Однако, если вы вернетесь назад и подумаете, как работало мое первое преобразование mapper.xml: Точка преобразования очень проста: в xml-файле нажмите ctrl+c на исходный тег if, а затем ctrl+v, чтобы изменить имя внутри.

Да, я использовал CV Дафа без мозгов. Заставило меня писать баги от смеха. Тип, который я передаю в orderStatus, является Byte, есть ли смысл судить с помощью ""?

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

В то же время я также благодарен за выполнение тестирования подразделения. В противном случае, когда я проверю свои одноклассники и бросим такие проблемы, я буду думать, что он не будет им использовать, и он подумает, что я слабая курица.

Несколько последних слов

После решения этой проблемы я еще проверил интернет и обнаружил, что некоторые люди сталкивались с такой проблемой, но первая статья, которую я нажал на поиск, было неправильным описанием, он сказал, что 0 будет считаться нулевым, в mybatis с чем бороться? Чувак, ты исходный код читал? Или мы не об одном и том же говорим?

А потом есть куча других статей, которые просто подбрасывают вам обходной путь и не пишут, почему это решит проблему. И такие результаты поиска, на мой взгляд, не идеальны, потому что трудно оставить глубокое впечатление, поэтому, когда вы или ваши коллеги снова столкнетесь с этой проблемой, вы скажете: «О, эта проблема, я сталкивался с ней раньше». Как решить я забыл.

Ты не говоришь глупостей?

Я написал абзац ранее в статье «Размышления после интервью с 15 аспирантами из колледжей 211/985 в выпуске 2020 года», который также уместен здесь:

конец

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

На что я больше надеюсь, так это на то, что когда вы столкнетесь с этой проблемой, вы закончите анализировать ее самостоятельно, и вы видели эту мою статью, когда искали в Интернете. Потому что то, что я проанализировал, всегда самое впечатляющее, а остальные статьи — просто суффиксы.

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

Если вы считаете, что статья неплохая, ваши лайки, комментарии, пересылка, обмен и оценка являются для меня величайшей поддержкой.

Спасибо за прочтение и за внимание.

выше.

Продолжайте выводить оригинальные статьи, более интересные оригинальные статьи, вы можете обратить внимание на общедоступный номер.