Comments 24
Слова "FetchType EAGER" в заголовке статьи явно лишние
Проблема Hibernate, кмк, в том, что за внешней простотой скрывается достаточно большой пласт дополнительных знаний, которые вам необходимо иметь. При этом, если их нет вы столкнетесь с проблемами только по ходу даже не разработки скорее всего, а уже эксплуатации продукта в продакшене. И эти знания должны быть у всех членов команды разработки, а это не всегда достижимо. И вот эта сложность, которая очень хорошо скрыта и завуалирована - главная проблема в использовании. Hibernate, кмк, очень хорош в прототипировании и mvp, после уже становится сложно.
Видел много команд, кто как раз запускался на Hibernate и после с него уходили.
На самом деле это не большой пласт, всем этим проблемам, как и их решениям уже сто лет в обед, нужно просто сесть, прочитать пару статей и выучить их уже наконец. Меня удивляют люди которые зачитываются и учат наизусть тома по базам данных на сотни страниц и их оптимизации, зато потом кричат: ой орм зло, тут столько проблем и все неочевидно, я лучше руками сам все напишу. Выучи уже наконец эти подходы и работай себе в удовольствие)
Плюсую
прочитать пару статей и выучить их уже наконец
Скорее солидную такую книгу страниц в 600. И все это постоянно забывается.
Моё мнение по хибернейту:
Какую проблему решает хибернейт? Борьба со сложностью? Нет, оно добавляет сложность, но маскирует её.
Экономия времени разработки? Возможно, но экономит на самом бутылочном горлышке приложения - общении с БД. Эта экономия вылазит боком при начале эксплуатации.
Остается третий вариант: все используют и мы используем. Кто мы такие чтобы сомневаться в умных дядях.
Возможно изначально это создавалось чтобы избавить от необходимости знать sql. Но на деле выходит что знать sql с хибернейтом надо ещё лучше, плюс приходиться изучать кишочки хибернейта.
Я виду один плюс - но большо-о-ой. Если вы стратегически правильно расставили аннотации Transactional - вам не надо вручную отслеживать и сохранять изменения извлеченных объектов обратно в БД. То есть - невозможна ситуация, когда вы изменили объект, а в базу его не записали обратно. Или наоборот - записали, а потом перезатерли другой копией того же объекта, но по-другому измененной. При ручном управлении базой данных такие ошибки почему-то рано или поздно возникают, а ловить их - тот еще цирк... А попытки это автоматизировать - приводят обратно к написанию куска Hibernate, только хуже и с глюками. Этот-то хоть уже вылизали за столько лет...
Вот это "мы изменили поле в объекте и оно должно автоматически сохраниться в бд" я считаю порочной практикой.
1) Это магия, сайд-эффект, ниразу не очевидное поведение
2) Похоже у вас в коде бардак, что вы не можете уследить за изменениями объекта и что несколько мест могут внести изменения и перезатереть, а вы об этом не знаете. Я предпочитаю идти по пути бизнес-действие = транзакция. Входные данные, их обработка, сохранение в бд. При чём в бд должны изменяться не все данные, как в случае с хибернейтом, а только изменяемые по этому бизнес-сценарию. Как такое реализовать в хибернейте не представляю. То что у вас объект с данными куда-то уходит, кто-то что-то там делает и вы не знаете что и зачем, и при этом ещё и хотите автоматом сохранить всё что там кто-то наделал - это караул.
Хибернейт получается поощряет такое
Я соглашусь с тем, что это сложный вопрос - и все существующие решения плохие: приходится выбирать чем жертвовать, а что важнее получить.
Смотрите - когда у вас простой CRUD - действительно, магия Hibernate выглядит избыточной. Чего проще - вытащили объект, модифицировали, сохранили... Но когда строится сложная система, которая должна работать у разных заказчиков без переписывания кода - приходится принудительно встраивать в систему возможность устраивания бардака (например, через хуки и события которые можно подключать позже через конфигурацию). И тут получается, что изначальный разработчик больше не контролирует жизненный цикл объекта так, как это было в простом сервисе. Потому что неизвестно, что напишут другие люди в этих хуках и кастомизациях.
Hibernate в этой части удобен тем, что он дает единые (и, в целом, понятные - хотя и непростые) правила жизненного цикла объектов и связи их с БД. Соответственно, что разработчик core functions, что разработчик хуков/плагинов могут рассчитывать на то, что эти правила будут соблюдаться (и баги в этой части уже вычищны).
Поэтому да - использование JPA/Hibernate не является строго обязательным. Можно посмотреть в сторону более легковесных решений типа MyBatis или чего-то еще. Но есть и ситуации, когда некоторое количество магии (эхм, давайте вспомним сколько ее в спринге?) делает жизнь легче...
Караул - это когда у вас на любой чих рукописный native sql, и при добавлении\изменении структуры в БД вам надо переписывать 100500 sql скриптов, а потом и тестов к ним. У вас вся работа встанет такими темпами и вы 90% времени будете бегать по проекту исправлять эти sql вместе с тестами к ним.
Я с таким уже сталкивался на примере mybatis. Даже не представляю что будет если все sql писать руками.
Как раз наоборот, оно убирает сложность, почитайте про архитектуру hh или stackoverflow, и почему они все используют ORM?
HH вообще прямо писали что они устали бороться с самописными рукописными SQL и в какой-то момент стало невозможно работать с кодовой базой, все просто остановилось.
Так и не понял почему оно вылазит боком? Добавляешь трэйсинг SQL в логи и смотришь какой у тебя SQL получается, если что-то не нравится то идешь читаешь доки\статьи как сделать лучше.
Когда у вас большая сложная система как раз-таки все эти рукописные SQL и есть самый геморрой с которым никто не хочет связываться, аля : оно как-то работает, давно пованивает, но последний человек, который туда залазил уже 10 лет как на пенсии, поэтому добавим ка мы памяти базе и забудем, когда в следующий раз всплывет эта проблема я уже уволюсь.
если я знаю как сделать лучше и какой запрос должен получиться, то зачем мне мешающий костыль hibernatе? Зачем мне постоянно проверять его работу и пытаться заставлять его не делать говно? Ради чего?
Когда у вас большая сложная система как раз-таки все эти рукописные SQL и есть самый геморрой с которым никто не хочет связываться, аля : оно как-то работает, давно пованивает, но последний человек, который туда залазил уже 10 лет как на пенсии, поэтому добавим ка мы памяти базе и забудем, когда в следующий раз всплывет эта проблема я уже уволюсь.
Это как раз про хибернейт. Что он там генерит никто особо не знает и не понимает, запросы в логе обфусцированы и их огромное количество, никто не понимает что с этим делать. Лучше добавим ещё памяти
Ага, а потом добавил/удалил одно поле и все приложение упало, потому что кто-то забыл в одном из 100500 мест сделать правку. Похоже, что вы вообще не понимаете в чем суть орм, и бизнес логику тоже в базе данных реализуете. Тогда наверное вам оно не нужно, тут соглашусь.
а зачем обкладываться дополнительными, протекающими абстракциями, нюансы которых надо знать в дополнение к знаниям о работе БД и SQL (а иначе вы не сможете анализировать проблемы производительности и строить адекватную схему БД), когда уже есть старый добрый SQL?
Прочитать пару статей? Сейчас как-раз на Baeldung статьи по Hibernate вычитываю.
250 статей, в среднем по 10 страниц = 2500 страниц. В день усваивается текст с новой информацией и конспектированием - по 60 страниц.
Итого, информации на 40 дней ежедневного изучения, вместо работы. С выходными - 2 месяца.
Пришел к аналогичным выводам. Этот фреймворк, вероятно, создавался с целью упростить процессы, но в итоге всё вышло сложным, неочевидным да еще и медленным. Я этими фичами вообще не пользуюсь и все работает без проблем, а вот в параллельном проекте да и там постоянно, что то происходит
На самом деле каждому инструменту свое применение. Если бездумно вытаскивать коллекции с данной аннотацией без ограничения по размеру вы скорее всего получите проблемы. Но если вы точно знаете что вам надо только один объект к которому вы будете вынуждены потом по всем его вложенным коллекциям пройтись чтобы их подтянуло из БД то почему бы и нет. Вопрос в поддерживаемости этого кода в дальнейшем но для этого есть например ассерты или еще какие то интерфейсные ограничения
Вот ничего себе рекомендация! Ленивая или немедленная выборка подчиненных/связанных объектов должна диктоваться логикой приложения и структурой таблиц! Иначе у вас на каждый чих будет случаться дополнительный запрос в БД - а это 10-60 мсек потерь чисто за то чтобы на другой сервер за данными сходить. Сто запросов - и вот уже на ровном месте полсекунды производительности потеряли...
Другое дело - что иногда eager начинают применять для того чтобы лечить веселые экспешены инициализации проксей/коллекций: "сессия уже закрыта, и транзакшн-менеджер не может начать новую в этом месте". Так делать, конечно же, не надо - это значит что приложение неправильно спроектировано, и объекты из БД утекают за пределы транзакции без ясного понимания зачем это делается! Если же бездумно ставить Eager на все такие случаи - то скоро по каждому чиху в память будет подниматься копия БД, и начнутся дикие тормоза и OOM...
Ключевая мысль автора в том, что "выборка подчиненных/связанных объектов должна диктоваться [только] логикой приложения...", и за это должен отвечать запрос в базу, а не сам объект. Если вы используете EAGER, то выборка будет диктоваться не "логикой приложения", а объектом. Если сейчас ваша логика предполагает обязательную загрузку связанной сущности, у вас все равно нет гарантии, что завтра не появятся дополнительные требования, по созданию запроса, где эта связанная сущность не будет нужна. Если появится такой запрос, "выборка будет диктоваться" уже не "логикой приложения".
Для этого конкретного, нового запроса, где связанная сущность вам не нужна, вы все равно будете ее доставать. Это значит, что запрос в базу будет расходовать ресурсы на эту ненужную сущность, кроме того, стратегия EAGER не защитит вас от n+1.
Дополнительные запросы всяко лучше, чем запрос всего и вся сразу. Вероятность что они понадобятся весьма мала. Потому короткие дозапросы весьма логичны. Ещё и нагрузку размазывают во времени. Вообще же счастье в балансе, конечно же. Который, в свою очередь опирается на архитектуру и логику работы системы. Проблема в том что многие разрабы об этом не задумываются.
Я устраивался на работу как SQL- программист, почти все задачи были на C#.
Сначала почитал про используемый фреймворк, потом три дня писал код на C# и смотрел какой SQL запрос он в итоге генерирует. По итогу знал как написать код чтобы получить оптимальный запрос. И я был уверен что ничего со временем не начнет работать как-то не так.
С начала статьи смежные концепции описываются в разном стиле, без подглядывания в справочник, непонятно что автор хочет донести.
Есть FetchType (EAGER, LAZY)
Есть FetchMode (JOIN, SELECT, SUBSELECT)
Есть @BatchSize - необязательная аннотация полей с FetchMode.SELECT
"Hibernate маппинг, формирует глобальный план выборки."
Непонятно, что подразумевается под Hibernate маппингом и под глобальным планом выборки.
Осилил несколько абзацев. Чем дальше, тем больше текст запутывает.
Мне результат перевода самому не очень понравился, но в целом крупицы золота, намыть можно и здесь) Если коротко, то какие поля и стратегии извлечения данных (FetchType), вы укажете при написании класса, сформирует глобальную модель выборки объекта из базы, то есть все запросы получение по id(getById), по любому из полей(getByField), получение всех объектов(findAll) и т.д., будут доставать объект в таком виде. Если в каких-то запросах, связанный объект, помеченный EAGER, вам не нужен, это значит, что вы будете расходовать на него ресурсы без необходимости. Так же нужно понимать, что используя EAGER, вы не застрахованы от n+1.
Не используйте JPA и Hibernate FetchType EAGER