2016-07-26 191 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