Глава 26. Лучшие практики

Оглавление
Пишите небольшие классы и отображайте их с помощью <component>:
Используйте класс Address для инкапсуляции street, suburb, state, postcode. Это способствует повторному использованию кода и упрощает рефакторинг.
Объявляйте свойства идентификатора в постоянных классах:
Hibernate делает свойства идентификатора необязательными. Существует ряд причин, по которым вы должны их использовать. Мы рекомендуем, чтобы идентификаторы были «синтетическими», то есть сгенерированными без бизнес-значения.
Определяйте натуральные ключи:
Определяйте натуральные ключи для всех объектов и сопоставляйте их с помощью <natural-id>. Реализуйте equals() и hashCode(), чтобы сравнить свойства, составляющие естественный ключ.
Помещайте каждое отображение класса в собственный файл:
Не используйте один файл для всех отображений. Отображайте com.eg.Foo в файл com/eg/Foo.hbm.xml. Это имеет смысл, особенно в командной среде.
Загружайте отображения как ресурсы:
Развёртывайте отображения вместе с классами, которые они отображают.
Рассмотрите объявление строки запроса:
Это рекомендуется, если ваши запросы вызывают не-ANSI-стандартные функции SQL. Объявление строк запроса в файлах отображения сделает приложение более переносимым.
Используйте подстановку переменных.
Как и в JDBC, всегда заменяйте неконстантные значения на «?». Не используйте строковые манипуляции для привязки неконстантного значения в запросе. Вы также должны рассмотреть возможность использования именованных параметров в запросах.
Не управляйте своими собственными подключениями JDBC:
Hibernate позволяет приложению управлять соединениями JDBC, но этот подход следует рассматривать последним. Если вы не можете использовать встроенных поставщиков подключений, рассмотрите возможность предоставления собственной реализации org.hibernate.connection.ConnectionProvider.
Рассмотрите использование настраиваемого типа:
Предположим, что у вас есть тип Java из библиотеки, которая должна быть сохранена (persisted ), но не предоставляет аксессоров, необходимых для отображения её как компонента. Вы должны рассмотреть возможность внедрения org.hibernate.UserType. Такой подход освобождает код приложения от реализации преобразований в/из типа Hibernate.
Используйте JDBC с ручным кодированием в узких местах:
В критичных для производительности областях системы некоторые виды операций могут выиграть от прямого JDBC. Не предполагайте, однако, что JDBC обязательно быстрее. Подождите, пока не убедитесь, что какое-то место является узким. Если вам нужно использовать JDBC напрямую, вы можете открыть Hibernate Session, обернуть операцию JDBC как объект org.hibernate.jdbc.Work и использовать это соединение JDBC. Таким образом, вы все равно можете использовать одну и ту же стратегию транзакций и незлежащего поставщика подключений.
Понимание очистки сессии (flushing Session):
Иногда Сессия синхронизирует своё постоянное состояние с базой данных. Производительность будет затронута, если этот процесс происходит слишком часто. Иногда можно минимизировать ненужную очистку, отключив автоматическую очистку или даже изменив порядок запросов и другие операции в рамках конкретной транзакции.
В трехслойной архитектуре рассмотрите использование отдельных объектов:
При использовании биновой (bean) архитектуры сервлета/сессии вы можете передавать постоянные объекты, загружаемые в сессионный бин, к и из слоя сервлета/JSP. Используйте новую сессию для обслуживания каждого запроса. Используйте Session.merge() или Session.saveOrUpdate() для синхронизации объектов с базой данных.
В двухслойной архитектуре рассмотрите использование длинных контекстов постоянства (long persistence contexts):
Транзакции базы данных должны быть как можно короче для лучшей масштабируемости. Тем не менее, часто бывает необходимо реализовать длительные транзакции приложений, одну единицу работы с точки зрения пользователя. Транзакция приложения может охватывать несколько циклов запроса/ответа клиента. Для реализации транзакций приложения обычно используются отделёные (detached) объекты. Соответствующей альтернативой в двухслойной архитектуре является поддержание единой открытой контактной сессии на протяжении всего жизненного цикла транзакции приложения. Затем просто отключайтесь от соединение JDBC в конце каждого запроса и снова подключайтесь к нему в начале последующего запроса. Никогда не используйте одну сессию для нескольких транзакций приложения, иначе вы будете работать со устаревшими данными.
Не обрабатывайте исключения как подлежащие возмещению (recoverable):
Это скорее необходимая практика, чем «лучшая» практика. Когда возникает исключение, откатите транзакцию и закройте сессию. Если вы этого не сделаете, Hibernate не сможет гарантировать, что состояние в памяти точно отражает постоянное состояние. Например, не используйте Session.load(), чтобы определить, существует ли экземпляр с данным идентификатором в базе данных; вместо этого используйте Session.get() или запрос.
Предпочитайте ленивую выборку для ассоциаций:
Используйте нетерпеливую выборку (eager fetching) экономно. Используйте прокси и ленивые коллекции для большинства ассоциаций для классов, которые вряд ли будут полностью сохранены в кэше второго уровня. Для ассоциаций с кешированными классами, где существует чрезвычайно высокая вероятность попадания в кеш, явно отключайте нетерпеливую выборку с использованием lazy="false". Когда выборка подходит для конкретного случая, используйте запрос с left join fetch.
Используйте шаблон открытой сессии в виде (open session in view) или дисциплинированную фазу сборки (assembly phase), чтобы избежать проблем с необработанными данными:
Hibernate освобождает разработчика от написания утомительных объектов передачи данных (Data Transfer Objects) (DTO). В традиционной архитектуре EJB DTO служат двум целям: во-первых, они работают над проблемой, что бины сущностей не являются сериализуемыми; во-вторых, они неявно определяют фазу сборки, где все данные, которые будут использоваться представлением, извлекаются и сортируются в DTO, прежде чем возвращать управление слою представления. Hibernate устраняет первую цель. Если вы не готовы удерживать контекст персистентности (сессию) открытым в процессе рендеринга представления, вам все равно потребуется фаза сборки. Подумайте о том, что ваши бизнес-методы имели строгий контракт со слоем представления о том, какие данные доступны в отделёных (detached) объектах. Это не ограничение Hibernate. Это фундаментальное требование безопасного доступа к данным транзакции.
Рассмотрите абстрагирование своей бизнес-логики от Hibernate:
Скройте код доступа к данным Hibernate за интерфейсом. Объедините шаблоны DAO и Thread Local Session. Вы даже можете иметь некоторые классы, сохранённые (persisted) с помощью JCBC, связанного с Hibernate, кодом, написанным вручную с использованием UserType. Однако этот совет предназначен для «достаточно больших» приложений. Это не подходит для приложения с пятью таблицами.
Не используйте экзотические отображения ассоциаций:
Практические тестовые случаи для реальных ассоциаций «многие-ко-многим» встречаются редко. В большинстве случаев вам нужна дополнительная информация, хранящаяся в «ссылочной таблице». В этом случае гораздо лучше использовать две ассоциации «один-ко-многим» для класса промежуточной ссылки. Фактически, большинство ассоциаций - это «один-ко-многим» и «много-к-одному». По этой причине вы должны действовать осторожно при использовании любого другого стиля ассоциации.
Предпочитают двунаправленные ассоциации:
Однонаправленные ассоциации сложнее запросить. В большом приложении почти все ассоциации должны быть проходимыми в обоих направлениях в запросах.