Удаление объекта завершается ошибкой из-за исключения в обработчике событий postRemove. Даже если исключение перехвачено, удаление завершается ошибкой, поскольку транзакция больше не может быть зафиксирована. Как это решить?
Полная история:
Мне нужно отслеживать некоторые удаленные объекты в веб-службе на основе Symfony 3.4, используя Doctrine.
Для этого я создал EventSubscriber, который обрабатывает событие postRemove, чтобы проверить, нужно ли регистрировать удаленный объект. В этом случае UUID объектов хранится в таблице DeleteLog th DB.
Это работает нормально, но в редких случаях сохранение DeleteLogEntry не удается, поскольку уже существует запись в журнале для данного UUID, которая должна быть уникальной.
Источником этой проблемы является какой-то сторонний код, который я не могу изменить сам. Как временное решение попробовал поймать UniqueConstraintViolationException. Это не решает проблему, так как теперь я получаю ConnectionException.
Transaction commit failed because the transaction has been marked for rollback only.
Можно ли решить эту дилемму?
Конечно, я мог бы проверить, существует ли DeleteLogEntry с данным UUID, прежде чем создавать новый. Но поскольку эта проблема возникает только в редких случаях, в большинстве случаев проверка будет отрицательной. Конечно, выполнение проверки в любом случае не оказывает катастрофического влияния на производительность, но просто кажется не лучшим решением.
Есть ли возможность поймать исключение и предотвратить пометку транзакции только как откат?




Нет, невозможно предотвратить пометку транзакции.
Doctine запускает вложенная транзакция для postRemove, и если это не удается, никакие другие транзакции не должны совершаться. Пометка транзакции только для отката (и даже закрытие диспетчера сущностей) является ожидаемым поведением в таком сценарии, потому что у Doctrine нет другого способа обеспечить согласованность, поскольку нет поддержки реальных вложенных транзакций.
Если производительность не является проблемой, хорошим вариантом будет проверка DeleteLogEntry.
Другие возможные обходные пути:
DeleteLogEntry позже, после первоначального удаления.DeleteLogEntry