Подтвердить что ты не робот

Laravel: Использование try... catch с DB:: transaction()

Мы используем DB::transaction() для нескольких запросов на вставку. При этом, если try...catch должен быть помещен внутрь или обернуть его? Нужно ли включать try...catch, когда транзакция автоматически завершится ошибкой, если что-то пойдет не так?

Пример try...catch завершение транзакции:

// try...catch
try {
    // Transaction
    $exception = DB::transaction(function() {

        // Do your SQL here

    });

    if(is_null($exception)) {
        return true;
    } else {
        throw new Exception;
    }

}
catch(Exception $e) {
    return false;
}

Противоположность, DB::transaction() упаковка try... catch:

// Transaction
$exception = DB::transaction(function() {
    // try...catch
    try {

        // Do your SQL here

    }
    catch(Exception $e) {
        return $e;
    }

});

return is_null($exception) ? true : false;

Или просто транзакция без попытки... catch

// Transaction only
$exception = DB::transaction(function() {

    // Do your SQL here

});

return is_null($exception) ? true : false;
4b9b3361

Ответ 1

В случае, если вам нужно вручную "вывести" транзакцию через код (будь то через исключение или просто проверить состояние ошибки), вы не должны использовать DB::transaction(), а вместо этого сверните свой код в DB::beginTransaction и DB::commit/DB::rollback():

DB::beginTransaction();

try {
    DB::insert(...);
    DB::insert(...);
    DB::insert(...);

    DB::commit();
    // all good
} catch (\Exception $e) {
    DB::rollback();
    // something went wrong
}

См. документы о транзакциях.

Ответ 2

Если вы используете PHP7, используйте Throwable в catch для обнаружения пользовательских исключений и фатальных ошибок.

Например:

DB::beginTransaction();

try {
    DB::insert(...);    
    DB::commit();
} catch (\Throwable $e) {
    DB::rollback();
    throw $e;
}

Если ваш код должен быть совместимым с PHP5, используйте Exception и Throwable:

DB::beginTransaction();

try {
    DB::insert(...);    
    DB::commit();
} catch (\Exception $e) {
    DB::rollback();
    throw $e;
} catch (\Throwable $e) {
    DB::rollback();
    throw $e;
}

Ответ 3

Вы можете обернуть транзакцию через try..catch или даже отменить их, здесь мой пример кода, который я использовал в laravel 5, если вы посмотрите внутри DB:transaction() в Illuminate\Database\Connection, что то же самое, что вы пишете ручную транзакцию,

Транзакция Laravel

public function transaction(Closure $callback)
    {
        $this->beginTransaction();

        try {
            $result = $callback($this);

            $this->commit();
        }

        catch (Exception $e) {
            $this->rollBack();

            throw $e;
        } catch (Throwable $e) {
            $this->rollBack();

            throw $e;
        }

        return $result;
    }

чтобы вы могли написать свой код, как это, и обработать свое исключение, например, отправить сообщение в форму через флеш или перенаправить на другую страницу. Возвращаемое возвратное внутреннее закрытие возвращается в транзакции(), поэтому, если вы вернетесь redirect()->back(), он не будет перенаправлен немедленно, потому что он возвращается в переменной, которая обрабатывает транзакцию.

транзакция Wrap

$result = DB::transaction(function () use ($request, $message) {
   try{

      // execute query 1
      // execute query 2
      // ..

      return redirect(route('account.article'));

   } catch (\Exception $e) {
       return redirect()->back()
          ->withErrors(['error' => $e->getMessage());
    }
 });

// redirect the page
return $result;

тогда альтернативой является булева логическая переменная и переадресация дескриптора внешней транзакции или если вам нужно восстановить причину неудачной транзакции, вы можете получить ее от $e->getMessage() внутри catch(Exception $e){...}