Рубрики
Без рубрики

Как использовать функции, зависящие от базы данных или спящего режима, без ущерба для переносимости

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

Автор оригинала: Vlad Mihalcea.

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

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

Хотя стандарт SQL доступен уже более 30 лет, не все реляционные базы данных реализуют его в полной мере. Некоторые системы баз данных предлагают нестандартные функции или различные способы обработки определенной функции, определенной стандартом SQL.

Наименьшим общим знаменателем многих СУБД является надмножество стандарта SQL-92. SQL-99 поддерживает общие табличные выражения (CTE), но MySQL 5.7 этого не делает. Только MySQL 8 добавляет поддержку CTE.

Хотя SQL-2003 определяет оператор MERGE , PostgreSQL 9.5 предпочел вместо этого операцию UPSERT .

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

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

Таким образом, для перехода на новую базу данных потребуется:

  • изменение сценариев резервного копирования
  • настройка репликация
  • мониторинг новой системы баз данных

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

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

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

Переносимость путем обобщения

Вы можете добиться переносимости, вычитая нестандартные функции. Если мы выбираем переносимость путем обобщения, то для каждой функции мы должны выбрать SQL-запрос, который работает как с Oracle, так и с MySQL. Однако это означает, что мы не можем использовать функции, специфичные для базы данных, которые могут быть более эффективными, чем общий SQL-запрос.

Именно так работает JPQL или HQL. Вместо поддержки всех функций, специфичных для базы данных, JPQL предоставляет только дополнительный набор функций, поддерживаемых подавляющим большинством систем реляционных баз данных.

Однако JPQL и HQL никогда не предназначались для полной замены SQL. В противном случае, почему вы думаете, что и EntityManager, и сеанс гибернации поддерживают выполнение собственных SQL-запросов ?

JPQL и HQL предназначены для извлечения сущностей, которые должны быть изменены приложением. Однако, если вам нужна проекция СВЕРХУ, требующая использования оконных функций или CTE, гораздо более подходит собственный SQL-запрос.

Переносимость по специализации

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

Итак, предполагая, что нам нужно создать отчет, который должен выполняться как на Oracle, так и на MySQL, мы можем абстрагировать методы DAO и предоставлять их через интерфейсы, а также иметь несколько реализаций для конкретной базы данных.

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

JPA-это всего лишь спецификация.

В нем описываются интерфейсы, с которыми работает клиент, и стандартные метаданные объектно-реляционного сопоставления (аннотации Java или XML-дескрипторы). Помимо определения API, JPA также объясняет (хотя и не исчерпывающе), как эти спецификации должны быть реализованы поставщиками JPA. JPA развивается вместе с самой платформой Java EE (Java EE 6 с JPA 2.0 и Java EE 7 с JPA 2.1).

Hibernate уже был полнофункциональной реализацией Java ORM к тому времени, когда спецификация JPA была выпущена впервые. Несмотря на то, что он реализует спецификацию JPA, Hibernate сохраняет свой собственный API как для обратной совместимости, так и для размещения нестандартных функций.

Даже если лучше всего придерживаться стандарта JPA, на самом деле многие поставщики JPA предлагают дополнительные функции, ориентированные на требования к уровню доступа к высокопроизводительным данным. Для этой цели Hibernate поставляется со следующими функциями, не совместимыми с JPA:

  • генераторы расширенных идентификаторов ( hi/lo , объединенные, объединенные-lo )
  • прозрачное пакетирование подготовленных заявлений
  • настраиваемые операторы CRUD ( @SQLInsert , @SQLUpdate , @SQLDelete )
  • статические/динамические фильтры объектов/коллекций (например, @FilterDef , @Filter , @Где )
  • сопоставление атрибутов с фрагментами SQL (например, @Formula )
  • неизменяемые сущности (например, @Неизменяемые )
  • дополнительные режимы промывки (например, Режим промывки.РУЧНОЙ , Режим промывки.ВСЕГДА )
  • запрос кэша второго уровня по естественному ключу данной сущности
  • стратегии параллелизма кэша на уровне сущностей (например, Кэш(usage.READ_WRITE) )
  • массовые обновления версий через HQL
  • исключить поля из проверки оптимистической блокировки (например, @OptimisticLock(исключено) )
  • версия менее оптимистичная блокировка
  • поддержка пропуска (без ожидания) пессимистичных запросов на блокировку
  • поддержка мультитенантности

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

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

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