2016-07-26 183 views
2

這裏是我的代碼:如何在交易時處理錯誤?

try { 
    $dbh_con->beginTransaction(); 

     $stmt1 = $dbh_conn->prepare("UPDATE activate_account_num SET num = num + 1"); 
     $stmt1->execute(); 

     $stmt2 = $dbh_con->prepare("SELECT user_id FROM activate_account WHERE token = ?"); 
     $stmt2->execute(array($token)); 
     $num_rows = $stmt2->fetch(PDO::FETCH_ASSOC); 

     if ($num_rows['user_id']){ 
      $_SESSION['error'] = 'all fine'; 

     } else { 
      $_SESSION['error'] = 'token is invalid'; 
     } 

    $dbh_con->commit(); 

    header('Location: /b.php'); 
    exit(); 

} catch(PDOException $e) { 

    $dbh_con->rollBack(); 

    $_SESSION['error'] = 'something is wrong'; 
    header('Location: /b.php'); 
    exit(); 
} 

正如你看到的,我的腳本回滾所有查詢時,有一個例外。但是當if ($num_rows['user_id']){false時它不會回滾。那麼我該如何回滾查詢,並在false的條件下保留錯誤'token is invalid'

+0

看到[這個答案](http://stackoverflow.com/a/11050776/2397327)拋出一個異常 –

+0

把你的修改出了try-catch –

回答

4

只要拋出一個異常,並像你已經這樣做。但不是一個捕獲聲明有兩個:

try { 
    $dbh_con->beginTransaction(); 

     $stmt1 = $dbh_conn->prepare("UPDATE activate_account_num SET num = num + 1"); 
     $stmt1->execute(); 

     $stmt2 = $dbh_con->prepare("SELECT user_id FROM activate_account WHERE token = ?"); 
     $stmt2->execute(array($token)); 
     $num_rows = $stmt2->fetch(PDO::FETCH_ASSOC); 

     if ($num_rows['user_id']){ 
      $_SESSION['error'] = 'all fine'; 

     } else { 
      throw new \Exception('token is invalid'); 
     } 

    $dbh_con->commit(); 

    header('Location: /b.php'); 
    exit(); 

} catch(PDOException $e) { 

$dbh_con->rollBack(); 

$_SESSION['error'] = 'something is wrong'; 
header('Location: /b.php'); 
exit(); 
} catch(Exception $e) { 

    $dbh_con->rollBack(); 

    $_SESSION['error'] = 'token is invalid'; 
    header('Location: /b.php'); 
    exit(); 
} 
+0

錯了..在這個'$ _SESSION ['error' ]'將包含「有錯誤的東西」,而不是「令牌無效」。 – stack

+0

然後簡單地移除'$ _SESSION ['error'] ='標記無效';'並且拋出你的異常 –

+0

爲什麼?我需要三條錯誤消息:'一切正常','令牌無效','有錯誤'。拋出異常讓我只有兩條錯誤消息。雖然我需要處理三個錯誤消息。 – stack

1

您的操作順序不好。在驗證令牌之前,您正在對數據庫進行更改。這是不好的安全設計。總是首先驗證所有輸入,然後才進行更改。

其次,獲取令牌的SELECT查詢不需要是事務的一部分。回滾SELECT不會產生影響,因爲這樣的查詢不會更改數據庫。所以我會做

try{ 
    select token 
    if token is not found, set error and exit 

    begin transaction 
    update active_account_num 
    ...other queries? 
    end transaction and commit 

    set success message, set header & exit 
}catch{ 
    rollback 
    set error message, set header & exit 
} 

在這種情況下,因爲只有一個查詢可以改變DB,你甚至不需要交易。

+0

你的方法只適用於我的問題中的那個例子。實際上,我的代碼更復雜,你的方法沒有用。 – stack

+0

對不起,哥們..對於這個答案,因爲它適用於上述例子。 – stack

+0

@stack無需道歉!我只是想幫忙。 – BeetleJuice

1

容易得多,如果你確保了表中包含的興趣

try { 
    $stmt2 = $dbh_con->prepare("SELECT user_id FROM activate_account WHERE token = ?"); 
    $stmt2->execute(array($token)); 
    $num_rows = $stmt2->fetch(PDO::FETCH_ASSOC); 

    if ($num_rows['user_id']){ 
     $dbh_con->beginTransaction(); 
     $stmt1 = $dbh_conn->prepare("UPDATE activate_account_num SET num = num + 1"); 
     $stmt1->execute(); 

     $_SESSION['error'] = 'all fine'; 
     $dbh_con->commit(); 

    } else { 
     $_SESSION['error'] = 'token is invalid'; 
     /* no transaction here, nothing to rollback */ 
    } 

    header('Location: /b.php'); 
    exit(); 

} catch(PDOException $e) { 

    $dbh_con->rollBack(); 

    $_SESSION['error'] = 'something is wrong'; 
    header('Location: /b.php'); 
    exit(); 
} 

的要求退出值後做更新()是多餘的也是一樣,可以被刪除。

+0

你的方法只適用於我的問題。實際上,我的代碼更復雜,你的方法沒有用。 – stack

+0

顯然,我們只能根據你的問題來回答我們的問題,我們不能把你的真實代碼寫出來。這種性質的問題是反對票和密切投票的磁鐵 – e4c5

+0

你是對的..但我的代碼在現實中真的很龐大,很難理解*(甚至很難閱讀)*。這就是爲什麼我簡化它.. – stack