@HellWalk

Как вручную управлять транзакциями в Doctrine?

Не понимаю как управлять транзакциями в Doctrine.

Допустим, что у нас есть воркер который слушает очередь и обрабатывает данные. Пример обработки 3-х запросов:
for ($i = 0; $i < 3; $i++) {

            $this->entityManager->getConnection()->beginTransaction();

            $entity = new OrderLog(); // entity для примера

            $entity->setRequest('request');
            $entity->setResponse('response');

            // ...какая-то другая логика и сущности

            $this->entityManager->persist($entity);
            $this->entityManager->flush();

            if ($i === 1) {
                // На втором запросе происходит ошибка и нужно сделать откат
                $this->entityManager->rollback();
            } else {
                // В остальных случаях все ок и делается коммит
                $this->entityManager->commit();
            }
        }


На третьей итерации получаю ошибку:

Doctrine\DBAL\ConnectionException: Transaction commit failed because the transaction has been marked for rollback only


Посмотрел официальную документацию, там очень расплывчатый комментарий на эту тему:

However, a rollback in a nested transaction block will always mark the current transaction so that the only possible outcome of the transaction is to be rolled back. That means in the above example, the rollback in the inner transaction block marks the whole transaction for rollback only. Even if the nested transaction block would not rethrow the exception, the transaction is marked for rollback only and the commit of the outer transaction would trigger an exception, leading to the final rollback. This also means that you cannot successfully commit some changes in an outer transaction if an inner transaction block fails and issues a rollback, even if this would be the desired behavior (i.e. because the nested operation is optional for the purpose of the outer transaction block). To achieve that, you need to resort to transaction nesting with savepoint.

All that is guaranteed to the inner transaction is that it still happens atomically, all or nothing, the transaction just gets a wider scope and the control is handed to the outer scope.


Складывается впечатление, что доктрина писалась только для обработки обычных http-запросов, когда в случае ошибки можно бросить исключение сделать rollback и на этом все закончить.

Хотелось бы узнать, как пример кода выше заставить работать.
  • Вопрос задан
  • 674 просмотра
Решения вопроса 1
Складывается впечатление, что доктрина писалась только для обработки обычных http-запросов

Правильное впечатление.
В таких случаях стоит явно пересоздавать EM после ролбэков.
HOW TO recover from rolled back transaction
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы