Как стать автором
Обновить

Spring Data JPA и upsert

Уровень сложностиСредний
Время на прочтение10 мин
Количество просмотров24K
Всего голосов 5: ↑5 и ↓0+5
Комментарии12

Комментарии 12

Целая статья вместо того, что бы на sql написать insert on conflict do update

не все хотят видеть нативщину в коде

ну так-то любой туториал можно сократить до букв RTFM ) я как раз и хотел написать про то, что еще можно сделать, кроме добавления в код нативного SQL

Для меня эта статья полезная, т.к. только изучаю java, spring. Про существование "insert on conflict do update" в postgres не знал

Скромно упомяну про возможность использования @Version в entity классе

я про нее вскользь говорил, когда писал про оптимистические блокировки, а так - да, хороший вариант избежать лишних блокировок на уроне БД

В итоге, первый insert выполнится успешно, а второй — свалится с ошибкой вставки по уникальному ключу (если вы, конечно, создали для внешнего идентификатора уникальный индекс).

По идее если используется сиквенса или UUID для внешнего идентификатора, то не будет дубликатов по ключу, но будет две одинаковые записи с разными ключами.

В статье я имею ввиду, что внешний идентификатор выдает не наша база, а какой-то сторонний сервис (поэтому он и внешний). Вы можете использовать как первичный ключ его, а можете сделать, чтобы первичный ключ генерировала база (я предпочитаю этот вариант). Но и во втором случае поле для внешнего ключа имеет смысл сделать уникальным, как раз чтобы ни при каких обстоятельствах не создались 2 записи с одинаковым внешним ID

NativeQuery возвращает количество измененных строк, а не сохраненный объект. Чтобы получить этот объект, нам надо выполнять отдельный запрос в БД, и при этом нет гарантий, что мы получим ровно то, что сами только что вставили;

Вы используете синтаксис Postgres. Просто допишите в конец "returning *" и DML запрос вернёт строки, подвергшиеся изменению.

Да, если мы используем PreparedStatement. Ну или вернее так - со Spring Data JPA это не сработает. При попытке объявить в репозитории модифицирующий метод, который возвращает не void и не int / Integer, вы получите ошибку, которая, собственно, и говорит:

Modifying queries can only use void or int/Integer as return type!

А вы уберите @Modifying. Строго говоря, тут уже не совсем DML, но микс из DML+DQL. Данная аннотация просто изменяет способ интерпретации результата запроса.

Можете нагуглить на эту тему много интересного и на stackoverflow и github issues. У меня такой код есть в продакшн, и никаких блокировок не нужно.

Хм, прикольно, не знал. Вернее, знал, что если мы хотим сделать insert / update с JPQL, то нам не дадут, потому что Not supported for DML operations [update ...] и ошибочно эктраполировал это и на nativeQuery. Но, да, с Native Query таких проверок нет и все работает. Спасибо!

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации