[英]How can I handle errors when there is transaction?
这是我的代码:
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'
呢?
只需抛出一个异常并像您已经捕获的那样捕获它即可。 但是除了两个catch语句,还有两个:
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();
}
您的操作顺序不好。 在验证令牌之前,您正在数据库中进行更改。 这是不良的安全设计。 始终首先验证所有输入,然后才进行更改。
其次,获取令牌的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
}
在这种情况下,因为只有一个查询可以更改数据库,所以您甚至不需要事务。
如果您在确保表中包含感兴趣的值之后进行更新,则容易得多
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();
}
对exit()的调用也是多余的,可以删除。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.