какую-то запись в базе с уникальным ключом. У меня код весь на апсерт, т.е. сначала проверяет, есть ли такая запись в базе, и либо модифицирует, либо вставляет. И все это обернуто в трай-кетч-DataIntegrityViolationException как раз на случай с двумя параллельными запросами. И все работает нормально со стороны клиента, запросы идемпотенты, возвращается 2 одинаковых ответа.
Но мне не нравится, что хибер и jdbc пишут в лог-еррор, что транзакция упала. С точки зрения бизнес-кода, это вполне валидное поведение, там рассчитано на то, что транзация упадет.
Можно как-то в спринге указать, что конкретно эта транзакция может упасть и не надо срать мне в логи?
Может такое быть что одновременно 2 тредки поймут что нет записи и создадут эти 2 одинаковые записи?
Такое постоянно и происходит. Тогда одна из транзакций упадет на DataIntegrityViolationException и опять перезапустится. В новой транзакции уже будет видна новая запись от другой транзации и запись просто будет обновлена
Можно сделать синхронизацию тредок, синхронизировать на каком-то id поле. И тогда не будут таких ошибок
В теории можно, но на практике запросы могут попасть на разные инстансы. Можно было бы конечно какой-то распределенный лок, но нафига? Оно все нормально отрабатывает, падающие транзакции — вполне валидный бизнес кейс
Написать аспект, который будет кетчить твой ексепшн?
А как это спасет? Может я не очень понимаю в аспектах, но моя проблема в том, что у меня лог.ерроры от хибера прилетают. Я только от этих лишних логов хочу избавиться
а что за бд используется? insert on duplicate key update не вариант прикрутить?
Они пишутся внутри хибера?
ага, и еще внутри jdbc
Эммм. А какой класс логгирует? Потому что сколько помню кидается исключение и ничего не логгируется
Ты же их перехватываешь и обрабатываешь?) Дальше прокидываешь?
Если логи действительно мешают (алерты на основе них, например), то в целом можно отключить логгер на уровне того класса и добавить свою логирующую обертку
В этих двух org.hibernate.engine.jdbc.batch.internal.BatchingBatch org.hibernate.engine.jdbc.spi.SqlExceptionHelper
я на уровне сервиса ловлю DataIntegrityViolationException, не логирую и перезапускаю транзакцию
А ты их сам включал?
у меня на org.* стоит уровень WARN
Я просто ни разу не видел что бы они что то логгировали
Сами живем с такой штукой, правда не сильно на неё ругаемся Выжимка из SqlExceptionHelper::logExceptions if (!previousErrorMessages.contains(sqlException.getMessage())) { LOG.error(sqlException.getMessage()); previousErrorMessages.add(sqlException.getMessage()); } Выше хорошо предложили, как по мне: отключить лог и залогировать самому в нужных местах
DataIntegrityViolation это не про конкурентный доступ, а про ограничения домена. Если эта ошибка возникает у тебя при конкурентном доступе значит неправильно написан запрос апсерта (он должен изменить, вставить или ничего не делать, но не бросать это исключение при конкурентном доступе). При правильной конфигурации база умеет разруливать одновременный доступ к одним и тем же данным.
у меня там не совсем настоящий апсерт, а апсерт для бедных — сначала делается repo.find, и если он ничего не вернул, то делает repo.insert. Да, можно на настоящий апсерт переписать и протестировать. Спасибо
Обсуждают сегодня