|
|
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
Добрый день, вопрос следующий. Имеется 3 сущности, например "от балды" : Юзер , у него много Постов и у него много Категорий . Т.е. отношения Юзера один ко многим (к таблице постов и таблице категорий). Упрощённо Код: java 1. 2. 3. 4. 5. Аннотации отношений я опустил, но имеем ввиду что загрузка Lazy. Вопрос: Как выбрать всех юзеров с уже заполнеными коллекциями posts и categories , при этом чтобы Hibernate выполнили всего 2 запроса, в первом выбрал всех юзеров с джоином постов, во втором всех юзеров с джоином категорий. Пока получилось сделать только так: Код: java 1. 2. 3. 4. Но в этом случае при дальнейшем обращении к категориям будет иметь на каждого юзера по дополнительному запросу в БД (через LAZY загрузку), что не есть хорошо (юзеров много). Теоретически нужно как-то выполнить 2 запроса в методе findAll(): Код: java 1. 2. Но я, к сожалению, не знаю как. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.09.2013, 16:16:20 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
Так? from User u left join fetch u.posts left join fetch u.categories ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.09.2013, 16:21:12 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.09.2013, 16:23:51 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
SkyFireorg.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags Есть такое. Bag это не упорядоченая коллекция в хибернейт. Дело в том, что когда запускается join на несколько коллекций, то хибер не может из результатов запроса понять где какой user.id, чтобы правильно распихать результат по коллекциям. Один из вариантов решения это замена Bag, на упорядоченый List. Для этого нужно в маппинге указать, как именно упорядочена коллекций. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.09.2013, 16:26:42 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
http://stackoverflow.com/questions/13334831/multiplebagfetchexception-thrown One way to do this is by specifying the Hibernate specific @IndexColumn or the JPA standard @OrderColumn on the relations. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.09.2013, 16:27:34 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
Blazkowicz, Вот с этим @OrderColumn у меня и проблема. Класс User является "владельцем" связи с категориями, т.е. Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. класс Category ничего не знает о User. При добавлении аннотации @OrderColumn(name="user_id") ловим следующее: ...hibernate.MappingException: Repeated column in mapping for collection: ru.example.unity.model.User.categories column: user_id Возможно я вообще не правильно все понял. Поправьте пожалуйста. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.09.2013, 16:44:49 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
Давайте с моделью сначала разберемся. То что категория ничего не знает о юзере - это мне понятно. Это логично. Откуда вот только тогда у категории user_id - этого я не понимаю. Т.е. должно быть many-to-many. И следующее. У всех категорий одного юзера - все user_id одинаковые. Поэтому сортировка по ним бессмысленна. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.09.2013, 16:49:14 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
Да, пример с категориями не очень удачный и больше подходит для многие ко многим. В действительности я "проецирую" этот упрощённый пример на свой реальный. Давайте условимся что "Юзеры" действительно относится к "Категориям" как многие к одному. Т.е. Categories iduser_idname12Авто22Вело33Вело44Спорт54Авто ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.09.2013, 16:58:53 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
SkyFire"Юзеры" действительно относится к "Категориям" как многие к одному. Точнее один ко многим конечно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.09.2013, 17:00:00 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
Логично попробовать @OrderColumn(name="id") ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.09.2013, 17:01:06 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
Теперь запрос строится верно (т.е. 2 лефт джоина обоих таблиц), но спустя 5 секунд: 17:09:40,244 WARN [org.hibernate.engine.loading.internal.LoadContexts] (http--127.0.0.1-8080-1) HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@4f96de53<rs=org.postgresql.jdbc4.Jdbc4ResultSet@68577956> 17:09:40,247 WARN [org.hibernate.engine.loading.internal.CollectionLoadContext] (http--127.0.0.1-8080-1) HHH000160: On CollectionLoadContext#cleanup, localLoadingCollectionKeys contained [100] entries 17:09:40,250 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/main].[unity-synch]] (http--127.0.0.1-8080-1) Servlet.service() for servlet unity-synch threw exception: java.lang.OutOfMemoryError: Java heap space Сам SQL возвращает порядка 200 строк, теперь я в полном "ступоре" :( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.09.2013, 17:16:31 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
JDK/bin/jvisualvm http://habrahabr.ru/post/61857/ ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.09.2013, 17:22:58 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
Blazkowiczfrom User u left join fetch u.posts left join fetch u.categories Здесь засада на уровне SQL. такой запрос возвращает строки для каждого поста со всеми категориями ( картезианское произведение ). 100 постов и 100 категорий это уже 10000 строк. Потом хибер пытается их собрать вместе удаляя лишнее, поэтому и ругался на Bag. Больше 2х таблиц в join пихать надо с большой осторожностью. Лучше грузить lazy с Batch Fetch . Оффтоп, недавно настраивали производительность в приложении и обнаружили что MS SQL Join для небольшой выборки делает в несколько раз медленнее, чем 2 отдельных запроса. основная база около 10 млн записей, на каждую в среднем 20 записей в дочерних таблицах. Для обработки выбираются 4 записи из основной таблицы, ц дочерними коллекциями. Удаление любовно составленных join fetch улучшило среднюю производительность в 5 раз. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.09.2013, 10:14:48 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
пролетевший Здесь засада на уровне SQL. такой запрос возвращает строки для каждого поста со всеми категориями ( картезианское произведение ). 100 постов и 100 категорий это уже 10000 строк. По-моему модель, в котором коллекции зачастую имеют десятки элементов и более это уже как минимум странно. Возможно даже глупо. Это всё равно что в отношении "Автомобиль - Район Регистрации" в "Районе" завести коллекцию "Автомобилей". пролетевший Потом хибер пытается их собрать вместе удаляя лишнее, поэтому и ругался на Bag. На Bag он ругался не из-за количества, а из-за того что в неупорядоченых списках он не может правильно найти нужные FK из результата запроса. пролетевший Больше 2х таблиц в join пихать надо с большой осторожностью. Хотелось бы уточнить: больше двух джоинов для ассоциаций one-to-many. пролетевший Лучше грузить lazy с Batch Fetch . Оффтоп, недавно настраивали производительность в приложении и обнаружили что MS SQL Join для небольшой выборки делает в несколько раз медленнее, чем 2 отдельных запроса. основная база около 10 млн записей, на каждую в среднем 20 записей в дочерних таблицах. Для обработки выбираются 4 записи из основной таблицы, ц дочерними коллекциями. Удаление любовно составленных join fetch улучшило среднюю производительность в 5 раз. Всё верно. Спасибо за коментарий. Я сразу про это как-то не вспомнил. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.09.2013, 10:29:34 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
BlazkowiczПо-моему модель, в котором коллекции зачастую имеют десятки элементов и более это уже как минимум странно. Возможно даже глупо. Спорный вопрос как мне кажется, сущности бывают разные. А по теме, с @OrderColumn так ничего и не вышло, к сожалению разбираться в чём проблема времени совсем нет. Проблема решилась заменой List<Category> на Set<Category>. Огромное спасибо всем за помощь. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.09.2013, 11:12:31 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
SkyFireСпорный вопрос как мне кажется, сущности бывают разные. Ну, давайте поспорим. В реальной жизни у юзера может быть сколько угодно постов. Т.е. у вас User.posts безразмерный список! Делать join на эту коллекцию это за гранью разумного. Даже lazy делать нужно с предельной осторожностью, потому что не факт что постраничная загрузка данных в этой коллекции будет работать. В противном случае мы отхватываем баги, когда неожиданно сервер будет уходить в OOME случайно загрузив User.posts. SkyFireА по теме, с @OrderColumn так ничего и не вышло, к сожалению разбираться в чём проблема времени совсем нет. Проблема решилась заменой List<Category> на Set<Category>. Да. Точно. Это второй рецепт, про который я успешно забыл. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.09.2013, 11:20:45 |
|
||
|
Hibernate несколько HQL для заполнения сущности
|
|||
|---|---|---|---|
|
#18+
Хорошо, вы меня переубедили :) У меня слишком мало опыта маппинге на дом-объекты да и в Java в целом. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.09.2013, 11:52:55 |
|
||
|
|

start [/forum/topic.php?fid=59&msg=38406299&tid=2128523]: |
0ms |
get settings: |
14ms |
get forum list: |
15ms |
check forum access: |
6ms |
check topic access: |
6ms |
track hit: |
266ms |
get topic data: |
16ms |
get forum data: |
4ms |
get page messages: |
78ms |
get tp. blocked users: |
2ms |
| others: | 260ms |
| total: | 667ms |

| 0 / 0 |
