Лучшая практика работы с гибернацией?

Я пишу веб-приложение с использованием Hibernate 3.

Итак, через некоторое время я заметил, что что-то было медленным. Поэтому я протестировал hibernate-профайлер и обнаружил, что hibernate сделает неоправданно много вызовов db для простой работы. Причина в том, что я загружаю объект (у этого объекта есть несколько "родителей" ), и у этих "родителей" есть другие "родители". Таким образом, базовый hibernate загружает их все, хотя мне нужен только базовый объект. Хорошо, поэтому я посмотрел на ленивую загрузку. Что привело меня в исключение Lazyloading, потому что у меня есть MVC webapp.

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

Должен ли я: 1. Копайте в ленивую загрузку. А затем переписать мое приложение для открытого сеанса? 2. Копайте в ленивую загрузку. А затем перепишите мое дао, чтобы быть более конкретным. Например. написав DAO-методы, которые возвратят объекты, созданные только для того, что необходимо для каждого случая использования? Может быть много дополнительных методов... 3. Скрестить спящий режим и сделать это сам? 4. Не могу сейчас думать о других решениях. Любые предложения?

Какова наилучшая практика?

Ответы

Ответ 1

  • Не используйте соединения, если это действительно необходимо. Они не позволят вам использовать ни ленивую загрузку, ни использование кеша второго уровня для ассоциаций.
  • Используйте lazy = "extra" для больших коллекций, он не будет извлекать все элементы до тех пор, пока вы его не спросите, вы также можете использовать метод size(), не получая элементы из DB
  • Использовать метод load(), если это возможно, поскольку он не выдает запрос выбора до его появления. Например. если у вас есть книга и автор, и вы хотите связать их вместе, это не будет выдавать никаких отборов, только одна вставка:

    Book b = (Book) session.load(Book.class, bookId);
    Author a = (Author) session.load(Author.class, authorId);
    b.setAuthor(a);
    session.save(b);
    
  • Используйте именованные запросы (в ваших файлах hbm или в @NamedQuery), чтобы они не анализировались во время каждого запроса. Не используйте API критериев до тех пор, пока он не понадобится (в этом случае невозможно использовать кеш PreparedStatement)

  • Используйте OSIV в своем веб-приложении, так как он будет загружать данные только тогда, когда/если это необходимо.
  • Используйте режимы только для чтения только для выборок: session.setReadOnly(object, true). Это приведет к тому, что Hibernate не будет сохранять исходный снимок выбранного объекта в постоянном контексте для последующих грязных проверок.
  • Пользовательский кеш второго уровня и кэш запросов для данных, предназначенных только для чтения и чтения.
  • Используйте FlushMode.COMMIT вместо AUTO, чтобы Hibernate не выдавал выбор перед обновлениями, но будьте готовы к тому, что это может привести к записи устаревших данных (хотя Optimistic Locking может помочь вам).
  • Посмотрите на пакетную выборку (размер партии), чтобы выбрать несколько объектов/коллекций за один раз, вместо того, чтобы выпускать отдельные запросы для каждого из них.
  • Выполняйте запросы типа "выберите новый Entity (id, someField) из Entity", чтобы получить только необходимые поля. Посмотрите на трансформаторы результатов.
  • При необходимости используйте пакетные операции (например, удаление)
  • Если вы используете собственные запросы, укажите явно, какие области кэша должны быть недействительными (по умолчанию - все).
  • Взгляните на материализованный путь и вложенные множества для древовидных структур.
  • Установите c3p0.max_statements, чтобы включить кеш PreparedStatment в пул и включить кеш оператора в вашей БД, если он по умолчанию отключен.
  • Используйте StatelessSession, если это возможно, оно преодолевает грязные проверки, каскадирование, перехватчики и т.д.
  • Не используйте разбивку на страницы (setMaxResults(), setFirstResult()) вместе с запросами, которые содержат объединения к коллекциям, это приведет к тому, что все записи будут извлечены из базы данных, а разбиение на страницы произойдет в памяти с помощью Hibernate. Если вам нужна разбивка на страницы, в идеале вы не должны использовать объединения. Если вы не можете избежать этого, снова - используйте пакетную выборку.

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

Ответ 2

Как я объяснил в этой статье или мой Высокопроизводительный JavaPersistence book, есть много вещей, которые вы можете сделать, чтобы ускорить работу Hibernate, например:

Ответ 3

Я считаю, что вы хотите просмотреть этот раздел в руководстве Hibernate.

Я ожидаю, что ваша оригинальная проблема "... неоправданно много db-вызовов..." является примером того, что они называют "проблема выбора N + 1". Если это так, у них есть варианты того, как с этим бороться.

  • Сделать тип выборки Присоединиться. Тогда у вас будет один выбор с несколькими объединениями, если нет промежуточных коллекций.
  • Делайте ленивую загрузку.
  • Возможно, некоторые другие, например FetchProfiles, с которыми у меня нет опыта.

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