为什么这个PDO回滚不起作用?

3
我正在使用PHP中的PDO和MySQL数据库。我想要做的是,每当插入失败时(例如在唯一字段中重复输入),都会抛出异常错误消息并回滚更改(在我的情况下不自动增加)。
这是我所做的,但它不起作用:
try {
    $email = $_POST['Email'];
    $FirstName = $_POST['FirstName'];
    $LastName = $_POST['LastName'];

    $query="INSERT INTO subscriber (Email,FirstName,LastName,CreateDate) VALUES (?,?,?,CURDATE())";
    $stmt = $conn->prepare($query);

    $stmt->bindParam(1, $email , PDO::PARAM_STR);
    $stmt->bindParam(2, $FirstName, PDO::PARAM_STR);
    $stmt->bindParam(3, $LastName, PDO::PARAM_STR);

    $stmt->execute();
}
catch(PDOException $e) {
    die ($e->getMessage().'<a href="addSub.php"> Back</a>'); 
    $conn->rollBack();
}

我哪里做错了?

这是编辑版本(插入整个部分),是否正确?谢谢。

if($_SERVER['REQUEST_METHOD'] == "POST"){


$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->beingTransaction();
try {

    $email = $_POST['Email'];
    $FirstName = $_POST['FirstName'];
    $LastName = $_POST['LastName'];


    $query="INSERT INTO subscriber (Email,FirstName,LastName,CreateDate) VALUES (?,?,?,CURDATE())";
    $stmt = $conn->prepare($query);


    $stmt->bindParam(1, $email , PDO::PARAM_STR);
    $stmt->bindParam(2, $FirstName, PDO::PARAM_STR);
    $stmt->bindParam(3, $LastName, PDO::PARAM_STR);

    $conn->commit();

}
catch(PDOException $e)
    {
    die ($e->getMessage().'<a href="addSub.php"> Back</a>'); 
    $conn->rollBack();
    }


try {
    $userID = $_SESSION['username'];
    $query="INSERT INTO list_sub (SubID,ListID) VALUES ('',$_SESSION[ListID])";
    $stmt = $conn->prepare($query);

    $conn->commit();

}
catch(PDOException $e)
    {
    $conn->rollBack();
    die ($e->getMessage().'<a href="addSub.php"> Back</a>'); 
    }

$conn = null;
}

我对此进行了一些编辑,以便您收到一些答案,但这实际上是非常局限的。die()相当自描述 :) - Tim Post
5个回答

9

这就是全部的代码吗?你需要开始一个事务才能提交/回滚:

$conn->beginTransaction();

try {
    ....
    $conn->commit();
} catch (PDOException $e) {
    $conn->rollback();
}

这是指将 $stmt->execute(); 更改为 $conn->commit(); 吗? - user782104
另外,如果我的编辑版本包含多个事务(例如插入两次),该怎么办? - user782104
不要误解,$stmt->execute()仍然需要执行,你需要在调用$conn->commit()之前先调用$stmt->execute()。我忙于工作,稍后会编辑帖子。 - Mike Purcell
它已关闭,你能看到我编辑过的帖子吗? - user782104
把 $stmt->execute() 放在 $conn->commit() 之前。 - Mike Purcell
请告诉我您是否已经使其正常工作。只需添加回 $stmt->execute(),您就可以继续了。 - Mike Purcell

6

PHP函数dieexit的别名,它会在打印指定信息后立即终止代码执行,因此第二行-回滚操作-不会被执行。


2
首先,您使用的die()将退出程序,因此在它之后的任何行都不会被执行。
然而,除此之外,还有其他一些需要确保设置正确的事项。
首先,请确保subscriberInnoDB表类型。MySQL的默认表类型(MyISAM)不支持事务。
其次,请确保您的PDO对象已将PDO::ATTR_ERRMODE设置为PDO::ERRMODE_EXCEPTION。您可以在构造函数中设置此属性或使用setAttribute()
第三,您需要在try子句之前实际开始一个事务,使用$conn->beginTransaction()

$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);需要将此代码放在程序代码的顶部吗? - user782104

1

没有保证AUTOINCREMENT值是连续的。

如果有两个并行的事务,同时插入同一张表,那么要么两者都接受编号中存在空缺这个情况,要么第二个事务必须等到第一个事务完成后才能开始。由于这会影响性能,因此“空缺是可以接受的”变体得以实现。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接