Как зафиксировать только часть транзакции PHP?

#php #mysql #laravel #pdo

#php #mysql #laravel #pdo

Вопрос:

Мне нужны идеи для решения проблемы, когда есть заказ, который нужно обновить, и платежи, которые должны быть созданы для этого заказа. Но если поручение не выполняется. Обновления, внесенные в заказ, должны быть отменены, но созданные для него платежи должны сохраняться.

Пример кода контроллера:

 $order = Order::find(1);

DB::beginTransaction();

    try {

        $order->update(['status' => 1]);
        chargeOrder ($order);

    } catch (PaymentErrorException $e) {

        DB::rollback();
        throw $e;

    } 
    catch (Exception $e) {

        DB::rollback();
        throw $e;

    }


DB::commit();
  

Пример функции, которая производит начисление заказа:

 function chargeOrder( $order ) {

    $payments_service->charge($order);
    $order->payments()->create( new Payment() );

}
  

Что мне нужно, так это то, что при возникновении исключения PaymentErrorException следует отменить только $order-> update(), но изменения, внесенные внутри функции chargeOrder, должны сохраняться.

Комментарии:

1. Вы имеете в виду функцию «CreateOrder», которой нет. Вы имеете в виду «chargeOrder»?. Вообще говоря, у вас есть шанс «исправить» вещи в catch-area. Это место для отмены обновления. Но у вас проблема в том, что вы не знаете, где произошло исключение. Если это произошло до «chargeOrder», изменения не сохраняются, потому что они никогда не происходят.

2. 1 — Да, это chargeOrder. 2 — Это просто пример кода, объясняющий проблему в двух словах. В примере исключение PaymentErrorException возникнет внутри chargeOrder(), если что-то не так произошло во время процесса начисления.

3. Не могли бы вы просто использовать новое соединение, чтобы сделать chargeOrder?

4. @madz Я думаю, что это альтернатива, нужно попробовать. Но если бы я мог справиться с этим без создания нового соединения, было бы лучше.

5. Не было бы лучше запустить chargeOrder, зафиксировать эти изменения, а затем запустить обновление и зафиксировать их отдельно? Я бы подумал, что если платежи всегда должны применяться, несмотря ни на что, то лучше рассматривать их как две отдельные транзакции

Ответ №1:

Если я правильно понимаю вопрос:

 $order = Order::find(1);
$previousStatus = $order->status;

DB::beginTransaction();

    try {

        $order->update(['status' => 1]);
        chargeOrder ($order);

    } catch (PaymentErrorException $e) {

        $order->update(['status' => $previousStatus]);

    } 
    catch (Exception $e) {

        DB::rollback();
        throw $e;

    }

DB::commit();
  

Комментарии:

1. Спасибо за воспроизведение, это работает, но это как раз то, чего я должен избегать. Реальный код обновляет многие модели, и откат их вручную был бы плохим решением : (