Повышение MyBatis Мало кто представляет, какие трудности постигают нас на пути внедрения уже знакомых технологий в новые системы.
Одна из неочевидных сложностей — подключение MyBatis к компонентам OSGi. Самая необычная трудность — скрыть ваши занятия в приватной части системы.
Мы не хотим выставлять наши объекты наружу.
Как мы прячем SIM-карту и карту MicroSD в чехол телефона.
Да, мы знаем, что такие вещи существуют, но не хотим их никому показывать.
То же самое касается объектов внутри компонента OSGi (пакета).
Итак, MyBatis, будучи сторонней библиотекой, не может добраться до приватных объектов.
А нам так хочется скрыть от всех свои тайны.
У меня чешутся руки, а стул скрипит от нетерпения.
Для нормальной работы нам необходимо научиться готовить МайБатис по частям.
Начнем с того, что конфигурацию лучше всего настраивать в Java-коде, а не в обычном XML. Поскольку у нас OSGi, доступ к базе данных происходит на уровне сервиса OSGi, реализующего интерфейс DataSource. Никто не расскажет вам, как настроить MyBatis для работы с распределенными транзакциями.
Их просто не существует на уровне MyBatis Framework. Вам придется использовать сторонние системы.
Одно мы знаем точно: в этом случае нам нужно указать менеджер транзакций — ManagedTransactionFactory. Для локальных транзакций необходимо выбрать JdbcTransactionFactory. Дальше начинается самое интересное — это классы, которые накладываются на параметры и результаты запросов.
Мы скрываем эти классы в приватной части компонентов OSGi. Здесь работает только одно решение — назначить каждому классу псевдоним.
В этом случае MyBatis создаст карту классов.
Ключами будет псевдоним класса, а значением будет класс.
Объект конфигурации, создаваемый в локальном загрузчике, имеет обычный доступ к классу из этой карты.
Динамическое создание объекта нужного класса не вызывает проблем.
Если мы забудем назначить псевдоним и указать полный путь к создаваемому классу в xml, MyBatis не сможет поднять этот класс.
Фабрика поднятия объектов была создана на уровне компонента MyBatis (пакета) и не имеет доступа к загрузчику классов нашего компонента OSGi. MyBatis просто отругает нас ошибкой на этапе чтения результатов выполнения SQL-запроса.
В MyBatis очень удобно использовать интерфейсы маппера.
Здесь вы можете пойти двумя путями хранения SQL-запросов.
Вы можете сохранить запрос в одноименном XML-файле, расположенном в том же пакете, где находится интерфейс.
Вы можете поместить запрос в аннотацию вызываемого метода.
В случае аннотаций указывать псевдонимы классов не обязательно.
MyBatis, обрабатывая аннотации, выполнит эту работу самостоятельно.
Ах да, можно устроить полную чехарду от XML-файлов и аннотаций.
В формате XML красивое описание resultMap, а в аннотациях ему соответствует полная лажа в нескольких методах.
Но в аннотации можно указать имя resultMap из XML-описания.
Также в XML-описании есть интересный функционал — импорт частей SQL-запросов.
Очень красиво выглядит, когда методы получают одни и те же объекты и отличаются только параметрами запроса.
Такую красоту невозможно повторить в аннотации.
Да, документация MyBatis рекомендует регистрировать в конфигурации все файлы запросов XML. Я бы сказал, что прописывать надо не XML, а интерфейсы (мапперы).
Система решит взять одноименный XML-файл рядом с интерфейсом.
Но, как показывает практика, эту работу можно отложить до лучших времен.
Скажем так, есть вероятность, что некоторые запросы будут выполняться настолько редко, что процедура вызова этих запросов окажется пустой тратой времени и памяти.
Производительность
Здесь мы плавно переходим к производительности.Производительность – это не увеличение производительности сервера базы данных.
Производительность с точки зрения затрат на хранение и обслуживание объектов и запросов.
Чем проще объекты, передаваемые в параметрах, и объекты, генерируемые в запросах, тем быстрее система их поднимает. Как было сказано, процесс поднятия можно отложить до лучших времен.
Тем самым сокращая время на первоначальную настройку MyBatis. При этом система не затрачивает особых усилий на анализ структуры классов по параметрам и результатам запроса.
Достаточно один раз зарегистрировать класс и система будет использовать готовую карту декомпозиции классов.
За это отвечает класс org.apache.ibatis.reflection.Reflector. Надеюсь, скоро мы увидим немного другую конструкцию — org.apache.ibatis.reflection.ReflectorFactory. Почему было сделано нововведение ReflectorFactory? Как уже говорилось выше, MyBatis запоминает структуру объекта один раз.
Хорошо, если объектов относительно немного.
Если объектов довольно много, ну, скажем, несколько десятков мегабайт, и используются они достаточно редко.
В этом случае производительность системы становится ее слабым местом.
Никто добровольно не очищает память от ненужных предметов.
В результате JVM сохраняет структуры неиспользуемых классов в специальном разделе Permgen Java 7. ReflectorFactory будет использоваться для очистки этого небольшого фрагмента памяти.
В настоящее время потеря настроек MyBatis (Config) приводит к высвобождению таких ресурсов, как память для хранения SQL-запросов и сопоставления интерфейсов.
MyBatis, забывая о конфигурации, забывает и о ReflectorFactory, тем самым разрушая структуру используемых классов.
В чем преимущество MyBatis перед реализациями JPA или JDO? Основным преимуществом является возможность динамического связывания большого количества объектов с базой данных и возможность забыть эти объекты.
Ну, честно.
Мы знаем, что JPA сканирует все классы на наличие аннотаций JPA Entity. Это потрясающе.
Что дальше? Больше ничего.
Нет информации о том, как JPA забудет об этих классах.
Автор в JDO DataNucleuse реализовал динамический подъем классов в OSGi. Намекнули, что система не выгружает объекты при остановке компонента OSGi. Прошли годы, а загрузки зарегистрированных объектов так и не появилось.
Я думаю, что аналогичные проблемы существуют и в других реализациях JPA.
Распределенные транзакции
Вторая тема, затронутая в статье, — это распределенные транзакции.MyBatis не имеет реализации для поддержки распределенных транзакций.
Относительно недавно в MyBatis появился очень интересный и полезный объект — SqlSessionManager. Это позволяет вам использовать один сеанс базы данных в одном потоке.
Сеансы в разных потоках не перекрываются.
Процесс открытия и закрытия сеанса легко передается обработчикам аннотаций.
Это используется практически везде, в библиотеках на базе Spring, CDI, Guice. Аннотации управления транзакциями можно найти повсюду.
И вы даже можете увидеть поддержку распределенных транзакций.
Но в распределенных транзакциях есть одна интересная хитрость.
Это возможность начать новую транзакцию в рамках уже запущенной транзакции.
Его название — «Требуется новый».
Что происходит с MyBatis? Это просто и грустно.
Работая в том же потоке, объект SqlSessionManager возвращает ранее открытое соединение.
То есть, открывая новую транзакцию, мы фактически забираем старое соединение в чужой транзакции.
Аварийное завершение вложенной транзакции не приведет к откату действий, поскольку все изменения произошли в рамках внешней транзакции.
Фиксация вложенной транзакции и откат внешней приведет к потере изменений, которые предполагалось внести во вложенную транзакцию.
Проект mybatis-guice предлагает решение столь деликатной проблемы.
Для объекта SqlSessionManager создается специальный ресурс XAResource. Контроллер транзакций TransactionManager управляет зарегистрированными ресурсами XA. Приостановка транзакции XA приводит к переключению информации о текущем сеансе на SqlSessionManager. Почему это появилось в mybatis-guice? Опять же виноват OSGi. OSGi имеет собственную спецификацию OSGi Blueprint. Он очень похож на Spring Framework. У них был один предок.
По ряду причин эти две концепции конфликтуют. Либо первое, либо второе.
Никакой сладости.
CDI Weld — это функция для веб-приложений.
Разработчики Weld так постарались, что написали это полезное решение исключительно для Интернета.
Вот и приходится искать решение, не мешающее жить среди шумных и не очень дружелюбных соседей.
Guice — это система, которая обычно сосуществует в рамках нескольких конфигураций, не мешающих друг другу.
Скажем так, две конфигурации легко могут ужиться в одном компоненте.
Один для работы с локальными транзакциями Jdbc, а второй для работы с распределенными транзакциями JTA. Наборы классов одинаковые, лишних аннотаций и xml-описаний нет. Даже настройка MyBatis происходит с помощью одного и того же метода в классе.
Надеюсь, что этот функционал скоро появится в новой версии mybatis-guice. Теги: #java #mybatis #osgi #jta #java
-
Отчет По Второму Минибару
19 Oct, 24 -
Как Я Пытался Взломать Биткойн
19 Oct, 24