В каких случаях лучше отказаться от JPA и использовать нативный JDBC
Что проверяют
Понимаете ли вы, за что платите, используя JPA, и можете ли назвать сценарии, где эта плата не окупается. Следом обычно спрашивают, можно ли смешивать оба подхода в одном сервисе и какие у этого подвохи.
Как отвечать
JPA (на практике Hibernate) даёт контекст персистентности: отслеживание изменений, кэш первого уровня, ленивую загрузку, каскады, оптимистичную блокировку через @Version. Это окупается, когда вы работаете с агрегатами: загрузили сущность, поменяли, сохранили. Когда задача другая, лучше опуститься ниже:
- массовые операции: вставка или обновление сотен тысяч строк. Каждая сущность попадает в контекст, растут dirty checking и память. Батчинг через
hibernate.jdbc.batch_sizeпомогает, но генерация ключаIDENTITYотключает пакетную вставку. На JDBC этоaddBatch(), а в PostgreSQL ещё быстрееCOPYчерезCopyManager; - отчёты и аналитика: CTE, оконные функции,
LATERAL, конструкции конкретной базы. Результат это плоская проекция, и управлять им как сущностью незачем; - потоковое чтение: миллионы строк через
setFetchSize(), не держа их в памяти. У драйвера PostgreSQL курсор работает только при выключенном автокоммите.
В Spring для этого не обязательно писать голый JDBC: есть JdbcTemplate, NamedParameterJdbcTemplate и более новый JdbcClient, из сторонних jOOQ и MyBatis. Они берут тот же DataSource и работают в той же транзакции @Transactional, так что смешивать можно точечно.
Цена перехода: ручной маппинг, нет ленивой загрузки и автоматического сохранения изменений, оптимистичную блокировку пишете сами.
Где спотыкаются
Говорят «JPA медленный». Чаще медленна конкретная загрузка: N+1, EAGER на коллекциях, лишние сущности в контексте. Это лечится внутри JPA, и интервьюер это знает.
Смешивают подходы и забывают про flush(). JDBC-запрос в той же транзакции не видит изменений, которые Hibernate ещё не отправил в базу, а обновление через JDBC не трогает уже загруженные сущности, и они остаются устаревшими.
Повторяют миф, что JPA не умеет хранимые процедуры. Для них есть @NamedStoredProcedureQuery и StoredProcedureQuery, это не повод уходить на JDBC.