[php] Laravel : DB :: transaction ()과 함께 try… catch 사용

우리는 모두 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;

또는 단순히 try … catch없이 트랜잭션

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

    // Do your SQL here

});

return is_null($exception) ? true : false;



답변

코드를 통해 트랜잭션을 수동으로 ‘종료’해야하는 경우 (예외를 통하거나 단순히 오류 상태를 확인하는 경우) 사용해서는 안되며 DB::transaction()대신 코드를 DB::beginTransactionDB::commit/로 래핑해야합니다 DB::rollback().

DB::beginTransaction();

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

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

트랜잭션 문서를 참조하십시오 .


답변

PHP7을 사용하는 경우 사용자 예외 및 치명적인 오류를 포착 하기 위해 Throwable in 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;
}


답변

당신이 깊은 내부를 보면 당신은 ,, 여기, 내가 laravel 5에 사용되는 내 예제 코드를 리버스도시켜 try..catch를 통해 거래를 포장 또는 수 DB:transaction()Illuminate\Database\Connection당신처럼 같은 수동 트랜잭션을 작성하는 것이 있습니다.

라 라벨 거래

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;
    }

따라서 이와 같은 코드를 작성하고 플래시를 통해 양식으로 메시지를 다시 던지거나 다른 페이지로 리디렉션하는 것과 같은 예외를 처리 할 수 ​​있습니다. REMEMBER return inside Closure는 transaction ()에서 반환되므로 반환 redirect()->back()하면 즉시 리디렉션되지 않습니다. 트랜잭션을 처리하는 변수에서 반환 되었기 때문입니다.

랩 트랜잭션

$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){...}


답변

복잡한 try-catch 블록보다 더 간단한 구문을 사용하여 해결할 수 있다고 생각하기 때문에이 질문에 대한 답을 제공하기로 결정했습니다. Laravel 문서는이 주제에 대해 매우 간단합니다.

try-catch를 사용하는 대신 DB::transaction(){...}다음과 같은 래퍼를 사용할 수 있습니다 .

// MyController.php
public function store(Request $request) {
    return DB::transaction(function() use ($request) {
        $user = User::create([
            'username' => $request->post('username')
        ]);

        // Add some sort of "log" record for the sake of transaction:
        $log = Log::create([
            'message' => 'User Foobar created'
        ]);

        // Lets add some custom validation that will prohibit the transaction:
        if($user->id > 1) {
            throw AnyException('Please rollback this transaction');
        }

        return response()->json(['message' => 'User saved!']);
    });
};

그러면 사용자와 로그 레코드가 서로 없이는 존재할 수 없음을 확인해야합니다.

위의 구현에 대한 몇 가지 참고 사항 :

  • 콜백 내에서 반환을 return사용할 수 있도록 트랜잭션 을 확인하십시오 response().
  • throw트랜잭션을 롤백하려면 예외 를 확인하십시오 (또는 Eloquent 내의 SQL 예외와 같이 자동으로 예외를 발생시키는 중첩 함수가 있음).
  • id, updated_at, created_at및 기타 필드는 사용할 수 AFTER 생성됩니다 $user(이 트랜잭션 (transaction)의 기간) 객체입니다. 트랜잭션은 보유한 모든 생성 로직을 통해 실행됩니다. 그러나를 AnyException던지면 전체 레코드가 삭제됩니다 . 이것은 예를 들어 자동 증가 열 id이 실패한 트랜잭션에서 증가한다는 것을 의미 합니다.

Laravel 5.8에서 테스트 됨


답변