Обработка исключений во время метода @Transactional в Spring - PullRequest
0 голосов
/ 03 мая 2018

Я пытаюсь выяснить, как лучше всего обрабатывать персистентные (и, возможно, другие) исключения в сочетании с @Transactional Spring. Для этого поста я просто собираюсь взять простой пример регистрации пользователя, который может вызвать DataIntegrityViolationException из-за дублирования имени пользователя.

Следующие вещи, которые я пробовал, и они не очень мне подходят:

1. Наивный подход: просто лови исключение

val entity = UserEntity(...)
try {
    repo.save(entity)
} catch (e: DataIntegrityViolationException) {
    // not included: some checks for which constraint failed
    throw DuplicateUsername(username) // to be handled by the controller
}

Это не работает, когда используется метод @Transactional, поскольку исключения постоянства не произойдут, пока транзакция не будет зафиксирована, что происходит вне моего метода обслуживания в оболочке транзакции Spring.

2. Промойте EntityManager перед выходом

Явно вызовите flush на EntityManager в конце моих методов обслуживания. Это заставит запись в базу данных и, таким образом, вызовет исключение. Однако это потенциально неэффективно, так как теперь я должен позаботиться о том, чтобы не сбрасывать несколько раз во время запроса без причины. Я также лучше никогда не забуду это, или исключения исчезнут в воздухе.

3. Сделай два класса обслуживания

Поместите методы @Transactional в отдельный пружинный боб и попытайтесь обойти их в основном сервисе. Это странно, так как я должен позаботиться о том, чтобы одна часть моего кода была в месте A, а другая - в месте B.

4. Ручка DataIntegrityViolationException в контроллере

Просто ... нет. Контроллер не занимается бизнесом (hue hue hue) при обработке исключений из базы данных.

5. Не лови DataIntegrityViolationException

Я видел несколько ресурсов в сети, особенно в сочетании с Hibernate, которые предполагают, что перехват этого исключения является неправильным, и что нужно просто проверить условие перед сохранением (то есть проверить, существует ли имя пользователя с помощью ручного запроса). Это не работает в параллельном сценарии, даже с транзакцией. Да, вы получите согласованность с транзакцией, но вы все равно получите DataIntegrityViolationException, когда «кто-то другой придет первым». Поэтому это неприемлемое решение.

7. Не используйте декларативное управление транзакциями

Используйте TransactionTemplate Spring вместо @Transactional. Это единственное удовлетворительное решение. Однако это немного более «неуклюже», чем «просто бросить @Transactional на метод», и даже документация Spring, похоже, подталкивает вас к использованию @Transactional.

Я хотел бы получить несколько советов о том, как лучше всего справиться с этой ситуацией. Есть ли лучшая альтернатива моему последнему предложенному решению?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...