Сохранение сущностей внутри Transactional
Часто встречаю такую логику при работе с Spring Data:
💁: Если в одном методе несколько обращений к БД, надо ставить Transactional.
К сожалению, на практике всё сложнее. В этом посте разберу работу с транзакциями на примере из задачки выше.
Итак, вот у нас код. Внутри метода несколько обращений к БД. Что может пойти не так?
Допустим, пользователь написал провокационный твит, потом одумался и удалил его. Но другие пользователи успели увидеть и настрочили гневных ответов. Что делать, если родительская сущность удалится после проверки existsById? Никто этому не мешает, удаление происходит в другом запросе.
Аналитик говорит: если родительский твит удалён, гневные ответы не сохраняем. Пользователю шлём сообщение "не получилось".
🤔 Как это реализовать?
Транзакция - это не аналог synchronized, она не запрещает другим транзакциям менять данные.
Задача решается на уровне ограничений в БД. Указываем, что parent_id - это ссылка на другую запись. Если на момент вставки не будет поля с таким id, получим DataIntegrityViolationException. Ну или concurrent update при уровне изоляции Repeatable Read и выше.
Уровень изоляции влияет на то, с какими данными мы работаем внутри транзакции. Но в данном случае это не важно. Итоговая проверка происходит в момент вставки. В коде выше Transactional не нужен.
Наблюдение из опыта: в Spring Data аннотация ставится за полсекунды, и осмысление иногда занимает столько же:) И либо Transactional вообще не ставят, и за счёт низких нагрузок проблем не возникает. Либо ставят на каждый чих и упираются в проблему с соединениями для вроде бы небольшой нагрузки.
Не надо так, будьте внимательнее с транзакциями в своем коде и на код-ревью❤️
Post #630
10.5K
- 👍 111
- ❤ 43
- 🔥 36
- 👎 29