Библиотека сайта rus-linux.net
OSCAR
Глава 16 из книги "Архитектура приложений с открытым исходным кодом", том 2.
Оригинал: OSCAR
Автор: Jennifer Ruttan
Перевод: А.Панин
Интегратор согласования (JPA)
Новейший метод доступа к базе данных заключается в использовании стандартного API для долговременного хранилища данных Java (Java Persistent API - JPA). В том случае, если бы в рамках проекта OSCAR было принято решение о переходе от использования Hibernate к использованию другого соответствующего стандарту JPA для объектов DAO и моделей API для доступа к базе данных, процесс миграции стал бы проще. К сожалению, так как подобные технологии являются слишком "новыми" для проекта OSCAR, практически не существует частей системы, которые фактически используют предлагаемый метод для получения данных.
В любом случае, позвольте мне дать пояснения относительно данного метода. Вместо файла с расширением .hbm.xml
вы можете добавлять аннотации к вашим объектам модели и DAO. Эти аннотации описывают таблицу базы данных, к которой следует обратиться, связи между полями объекта и столбцами базы данных, а также методы объединения запросов. Вся информация хранится в двух файлах и для работы больше ничего не требуется. На заднем плане все еще функционирует Hibernate, выполняя функции фактического извлечения данных из базы.
Все модели интегратора создаются с использованием функций JPA являются как замечательными примерами нового стиля доступа к базе данных, так и демонстрацией метода реализации новой технологии в рамках системы OSCAR. Данная модель все еще не используется во многих местах системы. Интегратор является относительно новым дополнением к исходному коду. Поэтому есть смысл использования этой новой модели доступа к данным вместо прямого использования Hibernate.
Затронем ставшую привычной в этой части раздела тему об аннотациях объектов POJO, которые используются в рамках JPA для реализации отлаженного процесса обработки данных. Например, во время процесса сборки интегратора создается файл SQL, который позволяет вам создать все необходимые таблицы базы данных - это чрезвычайно полезная возможность. Благодаря этой функции становится невозможным создание не соответствующих друг другу таблиц и объектов моделей (что вы можете сделать при использовании любого другого типа метода доступа к базе данных) и вам никогда не придется беспокоиться о именовании столбцов и таблиц. Прямые SQL-запросы не осуществляются, поэтому невозможно провести атаки на основе SQL-инъекций. Одним словом, этот метод "просто работает".
Принцип работы JPA может рассматриваться как аналогичный принципу работы системы ActiveRecord из состава фреймворка Ruby on Rails. Класс модели описывает типы данных, а также базу данных, которая хранит их; то же, что происходит с ними - добавление и извлечение - не должно волновать пользователя.
Недостатки Hibernate и JPAТехнологии Hibernate и JPA предоставляют некоторые преимущества при их стандартном использовании. В том случае, когда они используются для простого получения и сохранения данных, они позволяют значительно сократить время, затрачиваемое на разработку и отладку приложения.
Однако, это не означает, что их реализация в рамках системы OSCAR идеальна. Так как пользователь не описывает SQL-запросы, используемые при взаимодействии с базой данных для заполнения объекта POJO, соответствующего определенной строке, Hibernate предоставляется выбор лучшего способа осуществления данной операции. "Лучший способ" может быть представлен несколькими вариантами: Hibernate может выбрать метод простого извлечения данных строки или выполнить объединение запросов и получить большой объем информации единовременно. Иногда механизм объединения запросов может выходить из-под контроля.
Еще один пример: таблица casemgmt_note
содержит все записи пациентов. Каждая запись содержит большое количество относящихся к ней метаданных, но она также содержит список всех особых характеристик пациента, которые приходится учитывать при использовании информации из записи (эти характеристики могут быть представлены такими записями, как "отказ от курения", "диабет", которые разъясняют содержимое записи). Список особых характеристик пациента представлен в объекте записи в виде списка List<CaseManagementIssue>
. Для получения этого списка таблица casemgmt_note
должна объединяться с таблицей casemgmt_issue_note
(которая выступает в роли таблицы соответствия) и, наконец, с таблицей casemgmt_issue
.
Если вы захотите написать специфический запрос для Hibernate, что требуется в описанной выше ситуации, вам не придется использовать стандартный язык SQL - вместо него нужно использовать HQL (язык запросов Hibernate - Hibernate Query Language), который впоследствии будет преобразован в SQL (путем вставки внутренних имен столбцов для всех полей выборки) перед вставкой параметров и отправкой запроса серверу базы данных. В этом специфическом случае для написания запроса были использованы стандартные объединения без объединения столбцов и это означает, что тогда, когда запрос в конечном счете был преобразован в представление SQL, он был настолько длинным, что не было понятно, манипуляции с какими данными осуществляются. В дополнение к этому практически во всех случаях этот запрос не создает достаточно большой таблицы, процесс создания которой можно было бы заметить. Для большинства пользователей этот запрос выполняется достаточно быстро и поэтому он незаметен. Однако, эффективность этого запроса невероятно низка.
Давайте на секунду сделаем шаг назад. В тот момент, когда вы выполняете объединение двух таблиц, серверу приходится создавать временную таблицу в памяти. В большинстве случаев применения стандартных типов объединений количество строк результирующей таблицы равняется количеству строк первой таблицы, умноженному на количество строк второй таблицы. Таким образом, в том случае, если ваша таблица содержит 500,000 строк и вы объединяете ее с таблицей, содержащей 10,000,000 строк, вы создаете временную таблицу, состоящую из 5x1012 строк в памяти, после чего из нее осуществляется выборка данных и занятая память освобождается.
В одном из экстремальных случаев, с которым мы столкнулись, в результате объединения трех таблиц была создана временная таблица размером около 7x1012 строк, из которой в конечном счете было извлечено около 1000 строк. Эта операция заняла 5 минут и таблица casemgmt_note
была заблокирована в течение всего времени ее выполнения.
В конечном счете проблема была решена путем использования заранее подготовленных объявлений, которые ограничивали область выборки в первой таблице до момента ее объединения с двумя другими таблицами. Новый, гораздо более эффективный запрос снизил количество строк для выборки до приемлемого значения 300,000 и значительно увеличил производительность операции получения данных записей (время, необходимое для осуществления такой же выборки сократилось до 0.1 секунды).
Мораль этой истории достаточно проста: хотя Hibernate и выполняет свою работу достаточно хорошо, но пока операция объединения таблиц не достаточно точно описана и управляема (либо с помощью файла с расширением .hbm.xml
, либо с помощью аннотации объединения в рамках класса модели JPA), она может очень быстро выйти из-под контроля. Работа с объектами вместо SQL-запросов требует от вас передачи инициативы по реализации запроса библиотеке для доступа к базе данных и в реальности позволяет вам контролировать исключительно описание операции. Пока вы не начнете тщательно описывать операции, эта библиотека может работать некорректно в экстремальных условиях. Более того, в том случае, если вы разработчик баз данных, обладающий знаниями в области языка запросов SQL, эти знания не окажутся особо ценными при проектировании класса с поддержкой JPA, который лишает вас некоторого контроля над запросами, которым вы могли бы обладать в случае самостоятельной разработки SQL-запросов. В конечном счете можно сделать вывод о том, что для работы необходимы хорошие знания как в области языка SQL, так и в области аннотаций JPA, а также понимание того, как эти аннотации влияют на результирующие запросы.
Далее: Права доступа