
ORM — Object-Relational Mapping — Объектно-реляционное отображение — это технология, позволяющая связывать SQL-ые БД с ООП кодом. Самая известная из них — Hibernate.
Hibernate — очень красивая технология. Она формирует ощущение магии.
Ты просто создаёшь объект, — хлабысь! — он уже в базе данных. Никакого SQL, никаких соединений, никаких ResultSet. Всё происходит как будто само собой. Прелесть.
Именно поэтому отказаться от Hibernate так тяжело.
Это напоминает Кольцо Всевластия из «Властелина колец». Оно не просто давало силу — оно меняло сознание своего владельца. Оно внушало мысль, что без него уже нельзя. Что именно оно даёт власть и контроль.
Hibernate действует очень похоже. Он формирует ощущение, что именно он управляет данными. Что именно он связывает код с базой. Что без него всё развалится.
И ты начинаешь бояться.
Бояться, что без Hibernate придётся писать бесконечный SQL. Бояться, что потеряешь контроль над данными. Бояться, что любая операция с базой превратится в мучение.
Ты уже не представляешь себе проект без этой магии. Ты настолько к ней привык, что мысль «выкинуть Hibernate» кажется почти кощунственной. Кажется, будто вместе с ним исчезнет и сама возможность нормально работать с базой данных.
Но если всё-таки посмотреть на ситуацию трезво и задать себе простой вопрос:
А что на самом деле даёт Hibernate?
Кажется, что он ускоряет разработку. Возможно. Пока ты джуниор, ты восхищаешься тем, как легко всё работает. Создал объект, вызвал persist(), и данные уже в базе. Магия.
Но с опытом начинаешь замечать вещи, на которые раньше не обращал внимания.
Ты уже не восхищаешься отсутствием SQL. Ты начинаешь замечать сложность сопровождения, неожиданные побочные эффекты, необходимость помнить о десятках нюансов ORM. Тебе вдруг нужно знать этот самый SQL, который убегает в базу, чтобы разобратся в каком-то баге.
Пока это лишь отдельные мысли. Отдельные капли сомнений.
Каждая сама по себе ничего не меняет.
Но однажды наступает момент, когда последняя капля переполняет чашу.
У меня этот процесс начался с двух проектов.
Один был мой — на Hibernate. Я им искренне восхищался.
Второй был написан на обычном JDBC.
Каждый запрос выглядел примерно одинаково:
String sql = "select..."; PreparedStatement ps = ... ResultSet rs = ... model.setX(rs.getX(...)); model.setY(rs.getY(...));
Честно говоря, это выглядело ужасно. Попахивает утечками ресурсов.
Кринжово.
Допотопно.
Будто после современного автомобиля тебя посадили за трактор.
Но был один нюанс.
SQL-проект вся команда считала гораздо проще моего. Хотя он был почти в три раза больше. Я специально считал количество экранных форм и таблиц в базе.
И самое интересное — на том проекте джуниорам спокойно разрешали коммитить практически сразу. Никто особенно не боялся, что они что-нибудь сломают.
И они действительно почти ничего не ломали.
А к моему проекту на Hibernate разработчиков ниже уровня Middle старались вообще не подпускать.
Эта мысль тогда крепко засела у меня в голове, и дала парочку капель для будущего переполнения чаши.
Потом произошёл другой случай.
Бизнес попросил добавить очень простую функцию. По ID нужно было закрыть активность — просто установить один флаг в true. Код получился буквально элементарным. Я загрузил сущность через load(), выставил поле, а дальше Hibernate сделал всё сам. Нужен был всего один тест и он прошёл нормально. Ручное тестирование прошло нормальноё. Выкатили в прод.
Через две недели бизнес пришёл с претензией.
Не все активности закрывались.
Я был абсолютно уверен, что проблема не в моём коде.
Ну что там может не работать?
Я даже сказал бизнесу:
— Скорее всего, операторы иногда просто не нажимают на кнопку.
Бизнес сначала согласился.
Но потом опять вернулся.
Уже очень злой. Сеньёр написал один метод из одной строки и это не работало. Все посматривали на меня с немым вопросом. То ещё ощущение.
Я обложил всё логами. Выяснилось, что операторы действительно нажимали кнопку.
Но флаг иногда... не сохранялся.
Почему?
Я понятия не имел.
На меня смотрели все.
Для бизнеса эта функция напрямую влияла на деньги, поэтому давление было колоссальным и решить эту задачу нужно было немедленно.
Единственное решение, которое пришло мне в голову, — переписать эту функцию на чистом JDBC, с простым SQL-ем: update... where id=?.
Полчаса работы.
Выкатили.
И проблема исчезла.
Навсегда.
Позже я всё-таки разобрался.
Оказалось, что load() загружал всю сущность, а при коммите Hibernate сохранял обратно все её поля. Если параллельно кто-то изменял эту же запись, происходила потеря обновления. Моё изменение откатывалось другим сохранением.
Нужно было всего лишь поставить @DynamicUpdate.
Я знал про эту аннотацию. Но под давлением просто не вспомнил о ней.
Казалось бы, вывод очевиден.
Я просто получил новый опыт. Теперь я знаю, что в подобных случаях нужно ставить @DynamicUpdate. Стал ещё лучше разбираться в Hibernate. Значит, стал сильнее как разработчик.
Круто.
Именно так я тогда и должен был подумать.
Но мысли были совсем другими.
Не то, что-то с таким подходом. Не доложно быть так. Не может нормальная технология лажать в методе из одной строки. Почему для обновления одного булевого поля вообще нужно знать про существование @DynamicUpdate? Почему простейшая операция зависит от таких нюансов? Почему, чтобы система работала надёжно, я должен помнить десятки подобных особенностей?
И тогда в голове впервые прозвучал вопрос, который потом уже не давал мне покоя:
А зачем вся эта сложность?
Все знают одно из главных преимуществ Hibernate: он якобы практически не зависит от конкретной СУБД. Поменял диалект, параметры подключения — и приложение готово работать с другой базой данных. По крайней мере, именно так это обычно преподносят. Я тоже в это верил.
И тут произошло самое интересное.
Оба этих проекта нужно было переводили с Oracle на PostgreSQL.
Казалось бы, результат очевиден. Я был уверен, что мой проект мигрирует быстро и почти безболезненно, а разработчики SQL-проекта будут долго переписывать запросы и разбираться с различиями между СУБД.
Реальность оказалась ровно противоположной.
SQL-проект вышел в промышленную эксплуатацию уже через полгода. Мой проект на Hibernate — только через год. И это при том, что SQL-проект был примерно в три раза больше по объёму.
Причина оказалась простой. В SQL-проекте разработчикам нужно было лишь адаптировать SQL-запросы под новую СУБД. Да, часть запросов пришлось переписать, но это была понятная, локальная и достаточно быстрая работа.
В проекте на Hibernate всё оказалось иначе. Вместо обещанной независимости от СУБД пришлось разбираться с множеством особенностей ORM: несовместимостью HQL-запросов, изменившимися планами выполнения, падением производительности, нюансами диалектов и другими эффектами, скрытыми за «магией» Hibernate.
В итоге проект, который по объёму был значительно меньше, мигрировался почти в два раза дольше. И это в абсолютном аспекте — помните SQL-ый проект в три раза больше.
На практике всё оказалось совсем не так. Просто поменять диалект и параметры подключения к базе данных не получилось.
Из-под всей этой «магии» Hibernate сразу начали всплывать подводные камни. Например, в Oracle связка Query + HQL работала нормально, а в PostgreSQL — уже нет. Многие запросы, которые раньше казались вполне приемлемыми, стали работать непозволительно медленно, и их пришлось вручную анализировать и оптимизировать. Всплыли различия в диалектах, особенностях генерации SQL и поведении самого ORM.
И это лишь несколько примеров. Вместо обещанной независимости от СУБД мы получили длительную и трудоёмкую адаптацию приложения к новой базе данных.
Получается парадоксальная ситуация: технология, которая должна была скрыть различия между СУБД, на деле сама стала источником дополнительных проблем при миграции.
И тут я наконец прозрел: а зачем вообще нужна вся эта сложность, если её можно просто убрать и сделать систему на порядок проще?
Часто говорят, что писать SQL вручную и маппить ResultSet в модели через getXXX()/setXXX() — скучно и неудобно. Возможно. Но это всего лишь эмоции разработчиков.
Возникает вопрос: зачем за эти эмоции платить бизнесу? Зачем увеличивать стоимость разработки и особенно сопровождения только ради того, чтобы не писать несколько десятков строк понятного кода?
На мой взгляд, если технология требует изучения огромного количества внутренней механики, усложняет отладку, многопоточность и сопровождение, то она должна давать соразмерную выгоду. Если же выигрыш ограничивается тем, что разработчик пишет меньше SQL и меньше шаблонного кода, возникает закономерный вопрос: оправдывает ли это те дополнительные затраты, которые в итоге несёт бизнес?
Разработка в проекте занимает всего около 10% общего времени, поэтому даже заметное ускорение этого этапа мало что меняет. Да и само ускорение — ещё большой вопрос. Зато на сопровождение Hibernate уходит огромное количество времени. Он заставляет изучать весьма сложную технологию со всеми её EntityManager'ами, flush'ами, жизненным циклом сущностей и особенностями работы @Transactional. А когда в проекте появляется многопоточность, всё становится на порядок сложнее.
И, конечно, здорово, когда ты во всём этом разбираешься. Но неизбежно возникает вопрос: а зачем? Зачем тратить столько времени на изучение инфраструктуры, которая не решает бизнес-задачи, а лишь обслуживает саму себя?
А теперь давайте вспомним, что мир изменился.
Появились ИИ-агенты.
У них нет эмоций. Они не считают написание SQL унизительной или скучной работой. Они могут за секунды написать хоть десять, хоть сто запросов. Причём именно под вашу схему данных.
И самое главное — писать их теперь будете не вы.
Вам останется только прочитать код, проверить, что он делает именно то, что нужно, и при необходимости немного подправить.
Получается любопытная вещь.
Ещё совсем недавно одним из главных аргументов в пользу Hibernate было избавление разработчика от рутинного написания SQL.
Но если рутину теперь выполняет ИИ практически бесплатно, то этот аргумент начинает стремительно терять силу.
И тогда возникает закономерный вопрос.
Если SQL больше не является проблемой, то ради чего мы продолжаем платить за всю сложность Hibernate? За его внутреннюю магию, скрытые механизмы, нюансы жизненного цикла сущностей, flush, merge, @Transactional, @DynamicUpdate и десятки других особенностей?
В этот момент призрачная необходимость в Hibernate, если она ещё оставалась после всего сказанного, исчезает в ноль, от слова совсем.
За годы работы я понял одну простую вещь: самое дорогое в проекте — не разработка, а его сопровождение и развитие. А для этого важно, чтобы система ломалась как можно реже. И здесь действует почти универсальное правило: чем система проще, тем она надёжнее.
Hibernate — очень сложная технология, под капотом которой скрывается огромное количество внутренней механики. И проблемы могут возникнуть где угодно: в жизненном цикле сущностей, стратегиях загрузки, кэше, flush, транзакциях, особенностях dirty checking, генерации SQL, аннотациях, о которых легко забыть, и ещё десятках мест, не имеющих никакого отношения к бизнес-логике.И каждый раз, когда возникает очередная такая проблема, невольно задаёшь себе один и тот же вопрос.
А зачем?
Зачем усложнять систему, если можно сделать её проще?
Для себя я на этот вопрос уже ответил.
А появление ИИ лишь окончательно убедило меня, что возвращаться назад смысла уже нет.
От слова «совсем».
Комментарии (25)

gerbert_MX
23.06.2026 12:15лол
Базы это одна из тех сфер, где LLM должна работать ТОЛЬКО через обертку во избежание проблем
Сейчас ORM есть с минимальным оверхедом что по факту собирают те же самые sql-запросы из методов но БЕЗОПАСНО

accXak
23.06.2026 12:15В базу можно сделать безопасные запросы через этот ИИ, но код ваших llm не гарантирует, что они будут логически правильными. Главное в коде - предсказуемость. Если ты не знаешь, что делает код, код делает тебя.

Fragster
23.06.2026 12:15Конкретно это с ORM легко обходится через механизм оптимистических блокировок (в простейшем случае - поле версии и его проверку в транзакции перед записью). Зато есть всякие обзерверы, хуки на события моделей и куча всего приятного. Это еще один уровень абстракций, про который нужно понимать его преимущества и недостатки.
А в SQL легко можно можно получить неконсистентное состояние объекта, потерянные обработчики зависимых объектов и прочее и прочее, либо придется написать свой маппер строки БД в объект и обратно и кучу лапши для технического обеспечения того, что в ORM идет из коробки, причем для каждого объекта свое. Я понимаю, "фатальный недостаток" и вот это все, но в итоге стоимость поддержки системы с хорошим и типовым набором библиотек дешевле, а разработка - проще.
igorhak
23.06.2026 12:15А что мешает написать свой механизм блокировок с помощью pg_try_advisory_xact_lock/pg_advisory_xact_lock?

vyacheslavchulkin
23.06.2026 12:15Это лишь капля в море, если копнуть глубже всю экосистемку джавы, то там очень много инструментов которые делали чтобы упростить жизнь, но получилось что усложнили, поверх этого начали решать то что усложнили и усложнили ещё больше.то усложнили и усложнили ещё больше.

Count_s
23.06.2026 12:15Вопрос во многом еще и в архитектуре: ORM имеет свойство протекать в бизнеслогику, а это нарушение изоляции - хранение стоит абстрагировать от использвоания. И это можно делать и с ORM, но кто ж так будет делать. При правильной нарезке слоев BLL/DAO/DAL на нижнем уровне вообще все равно что использовать, хоть файлы, хоть sql, хоть ORM (но зачем)

accXak
23.06.2026 12:15Простите, прочитал только заголовок.
Конечно есть смысл в ORM. Естественно, если брать в расчет объем работ с базой данных. И если ты собираешься дальше работать с этим кодом.
А если учитывать ИИ и не использовать обсуждаемые абстракции - верный путь к деградации. Через месяц ты уже не поймешь, что делает робот в твоем коде. Если сейчас понимаешь...

werevolff
23.06.2026 12:15Так-то ИИ - это тоже кольцо всевластия, которое внушает владельцу, что без него нельзя писать код.

pkokoshnikov
23.06.2026 12:15Такое ощущение что прочитал ии текст.
Никакой конкретики, хоть бы одну проблему разобрали детально.
Много воды. Однословные предложения, как у видео для сна с YouTube
По смыслу статьи.
ИИ и hibernate хорошо знает и все подводные камни в нём. Вряд ли тут есть большая разница.
Hibernate позволяет достаточно просто работать с вложенными доменными моделями. Сам следить что было изменено внутри модели и сохраняет только изменнные объекты. Можно больше сосредоточится на написании бизнес логики. В противном случае придётся писать достаточно трудоёмкий код по отслеживанию изменений или просто написать кучу мелких скриптов склеенных в сервисном слое. Читать и разбирать это потом та ещё забава.
Если модель простая и плоская в hibernate конечно смысла особо нет, пихать его в любой проект не стоит.

bambazamba
23.06.2026 12:15Вдумчивая нормализация баз данных при проектировании часто помогает решить проблему еще до ее возникновения. Да, я согласен, что я даже не совет дал, а как сова-стратег из анекдота про мышей, но все же: если проблема в ORM, то и чистый SQL запрос может не помочь, но очень часто это решается переосмыслением бизнес объектов и отношений между ними. Да, иногда надо подстроить бизнес сущности под нормализацию, но оно того стоит. Попробуйте глянуть на проблему под другим углом. Мне помогает.

notlimitedwolf
23.06.2026 12:15Вообще странная статья немного. В названии orm, но внутри один лишь jpa. С примером автора из жизни столкнуться можно и используя обычный sql: технологический стек не имеет разницы, если два обновления наслоятся друг на друга. Это решается архитектурно оптимистичными блокировками.
Различные orm (в тч hibernate), сам ЯП Java, используем бд - это технологии. У любой технологии есть много подковырных и сложных моментов, которые неочевидны новичкам. Как гласит древняя истина, "использование orm не является антипаттерном. Слепое использование orm и нежелание в нём разбираться является антипаттерном"

Kerman
23.06.2026 12:15Часто говорят, что писать SQL вручную и маппить ResultSet в модели через getXXX()/setXXX() — скучно и неудобно. Возможно. Но это всего лишь эмоции разработчиков.
Это не эмоции разработчиков. Ручной маппинг - это непаханное поле для граблей и ошибок. ORM делает маппинг за тебя и он даёт гарантию, что маппинг всегда корректный и там нет ошибок. В отличии от ИИшечки, кстати.
ORM - это та штука, которая не просто делает эту работу с гарантией, она ещё и здорово облегчает переделку/рефакторинг.

Pompei Автор
23.06.2026 12:15Вы забываете про тесты. Все обращения в БД можно вынести в отдельные классы, и их ещё протестировать, чтобы все маппинги были корректными. Ну и получаеться, что "ручной маппинг" на практике ни когда не создаёт проблемы. Наоборот, он позволяет более точно регулировать поток данных между БД и сервером приложений. Например для сущности "Клиент", можно создать несколько моделек: ClientRecord - для заполнения таблиц, ClientDetailsTopLevel - для заполнения верхнего уровня формы, CLientRow - для комбобокса. И повторю - это всё должно быть обставлено тестами, которые контрлируют корректность мапинга. И чем больше текстов, тем лучше. А ИИ их ОЧЕНЬ хорошо и быстро пишет

hachucha
23.06.2026 12:15А можно использовать orm и не тестировать маппинг, ведь ты и так знаешь, как она работает. Тесты (юнит) вообще мне кажутся искуственной и редко применимой концепцией, т.к. отлавливаюит только предсказуемые ошибки, а не те, которые обычно случаются, или вообще ничего не ловят, т.к. при изменении кода меняются и ожидания от него. Теоретически можно написать тесты, которые полезны, но на практике это ощущается сложнее, чем сама программа.

svz
23.06.2026 12:15Утверждал это ещё лет 10 назад. Ваши запросы или слишком простые, чтобы использовать на них hibernate, или слишком сложные, чтобы использовать на них hibernate.

vitiok78
23.06.2026 12:15ORM всегда много обещает, но потом не сдерживает ни одного своего обещания.
ORM была в своё время очень хороша, когда надо было быстро создавать однотипные проекты. Время выхода на рынок простого проекта было весьма коротким. Это очень нравилось бизнесу.
Но в моей практике практически любой проект который пережил год, начинал страдать от борьбы не со сложностью бизнес логики или кода, а от борьбы с ORM.
Первая жертва ORM - это производительность. Тупой инструмент не может учесть все нюансы, и генерирует плохой SQL. В итоге, чтобы исправить проблемы производительности, я пишу SQL в проекте с ORM. А Когда приходишь в в чужую церковь со своим уставом... начинаются проблемы.
База данных-это уже довольно высокоуровневый инструмент, и SQL уже является абстракцией невероятно высокого уровня. Вводить такую сложную абстракцию, как ORM, поверх уже довольно сложной абстракции считаю довольно глупым и самонадеянным поступком.

onets
23.06.2026 12:15Для баланса - однажды тоже довелось сделать поддержку двух бд - oracle и ms sql. Но был c# + nhibernate. Все прошло гладко, за 3 часа. Но было это 3000 лет назад.
И как я уже писал недавно в коментах - на том проекте еще был store procedure api (как rest api, только хранимки). Из-за того что следил, чтобы код держали близко к старому стандарту типа sql 92 - потребовались незначительные изменения.
Продукт был в банковской сфере, кодили его 5 программистов. Это чтоб примерно понимать сложность.

apevzner
23.06.2026 12:15Не то, что-то с таким подходом. Не доложно быть так. Не может нормальная технология лажать в методе из одной строки. Почему для обновления одного булевого поля вообще нужно знать про существование @DynamicUpdate? Почему простейшая операция зависит от таких нюансов? Почему, чтобы система работала надёжно, я должен помнить десятки подобных особенностей?
Это называется Leaky abstraction. https://en.wikipedia.org/wiki/Leaky_abstraction
Увы, из удобных высокоуровневых абстракций иногда подтекают их низкоуровневые детали реализации.
Но если рутину теперь выполняет ИИ практически бесплатно, то этот аргумент начинает стремительно терять силу.
И тогда возникает закономерный вопрос.
А если из ИИ подтечёт? :)

pompei2
23.06.2026 12:15За ИИ нужно смотреть. И тут главное чтобы понимать что читаешь, и чтобы читать было просто.

next_account
23.06.2026 12:15читал статью, а про себя думал - да это же один в один мой опыт с ReactJS - поначалу jsx завораживал, но когда дело дошло до асинхронных операций пришлось разбираться в неочевидных тонкостях, все эти саги и генераторы для простых вещей (не знаю как сейчас обстоят дела у реакта, это было лет 6-8 назад). но нельзя сказать что этот опыт был бесполезным - это были первые шаги в мир функционального программирования (чистые функции и тд).

pompei2
23.06.2026 12:15С приходом ИИ для работы на клиенте тоже нужно менять мышление. Зачем придумали Angular и React (и прочие фреймворки)? Ответ: чтобы быстрее программировать. Чтобы малыми силами делать бОльшую функциональность. Но с ИИ это уже не нужно. А значит не нужны и Angular и React. Достаточно TypeScript, кастомные теги, и async-функции.
И это будет быстро, потому что это будет делать ИИ.
А TypeScript и async-функции чтобы проще читать.

next_account
23.06.2026 12:15вам виднее, я не стремлюсь писать быстрее - для меня это хобби и пишу только в удовольствие. (вайбкодинг тоже пробовал - поначалу поразило а потом по мере роста проекта появлялось куча нерабочего кода и т.д., я использовал локальные модели на процесоре в основом, скорость около 1 т/с 4Q qwen3.6 27b. пришел к тому что раз в несколько дней прошу ИИ изучить проект и предложить улучшения - часть из них заслуживает внимания.) после реакта я был в восторге от Elm, но для быстрого прототипирования вспотел переписывать сериализаторы/десериализаторы - как я понял Elm очень бы себя хорошо показал в командах где отдельно фронт/бэк и где уже есть спецификация апи. сейчас я в восторге от elixir - phoenix. (но любовь к js осталась, да и node.js оказалась популярной штукой и опыт с ним тоже не лишний).
schekinfs
SQL - это то место, где будешь "ловить ножи", особенно с ИИ. Если руками пишешь (прямо проверяешь все хотя бы), да.
С ИИ так советовать.... будет красиво, опасно красиво. И потом будут статьи, код написанный ИИ сломали, инекция и т.п. А джуняндра скажет, это не я, это ИИ такая вот, "не сделала хорошо злая такая"
igorhak
В Хибере действительно много сайд-эффектов, которые ещё и ведут себя по разному от версии к версии. В отчётах, например, он вообще не пригоден к использованию в виду сложных выборок и отсутствия cte.
Последнее время приходилось писать запросы на 300-500 строк, в чем очень хорошо помогал ИИ, и так же помогал оптимизировать эти запросы. Я просматривал план сам, оптимизировал все и потом просил оценить и оптимизировать ещё ИИ, время на написание этих запросов существенно сократилось.
Коллеги из параллельной команды, в .net правда, пытались использовать “всю мощь ОРМ” и получили плачевные результаты, сложные запросы, которые строила ОРМ безумно грузили БД и в частности дисковую систему и за большого количества последовательных чтений. Оптимизировать индексами такие запросы не удавалось, так как они имели большую вложенность на больших объемах данных.