PDO:事务不会回滚?

发布于 2024-08-24 18:09:49 字数 1926 浏览 2 评论 0原文

我正在阅读关于 PDO 的本教程,并来到了关于交易的要点。跳过连接部分,我有这个 php 代码:

try
{
    $db->beginTransaction();

    $db->exec('DROP TABLE IF EXISTS animals');

    $db->exec('CREATE TABLE animals ('
        .'animal_id MEDIUMINT(8) NOT NULL AUTO_INCREMENT PRIMARY KEY,'
        .'animal_type VARCHAR(25) NOT NULL,'
        .'animal_name VARCHAR(25) NOT NULL)'
        .'ENGINE=INNODB');

    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("emu", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("funnel web", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("lizard", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("dingo", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("kangaroo", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("wallaby", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("wombat", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("koala", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("kiwi", "bruce")');

    $db->commit();

    echo 'Table re-created and data entered successfully.';
}
catch(PDOException $e)
{
    $db->rollback();

    echo $e->getMessage();
}

它运行得很好,就像我想象的那样,除非我在某处输入错误。就像如果我在第四个插入语句中犯了一个错误,我会在数据库中找到三种动物。但我认为事情应该回滚,这意味着我会像运行此脚本之前一样找到数据库。

我是否误解了什么?我缺少什么?事务和回滚函数是否执行了我认为应该执行的操作以外的操作? drop 和 create 语句是否以某种方式“破坏”了事务?这是怎么回事?


更新:如果我移动 $db->beginTransaction(); 行,则事务仅在表完成后才开始创建后,我得到了我所期望的行为。因此,如果第三个插入语句失败,则在事务回滚后我将得到一个空表(因为它刚刚重新创建)。仍然想知道为什么当 drop 和 create 语句在事务中时它不起作用......

I am going through this tutorial about PDO and have come to the point about transactions. Skipping the connection parts, I have this php code:

try
{
    $db->beginTransaction();

    $db->exec('DROP TABLE IF EXISTS animals');

    $db->exec('CREATE TABLE animals ('
        .'animal_id MEDIUMINT(8) NOT NULL AUTO_INCREMENT PRIMARY KEY,'
        .'animal_type VARCHAR(25) NOT NULL,'
        .'animal_name VARCHAR(25) NOT NULL)'
        .'ENGINE=INNODB');

    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("emu", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("funnel web", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("lizard", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("dingo", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("kangaroo", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("wallaby", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("wombat", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("koala", "bruce")');
    $db->exec('INSERT INTO animals (animal_type, animal_name) VALUES ("kiwi", "bruce")');

    $db->commit();

    echo 'Table re-created and data entered successfully.';
}
catch(PDOException $e)
{
    $db->rollback();

    echo $e->getMessage();
}

It runs great and like I thought it would, except if I put in an error somewhere. Like if I created a mistake in the fourth insert statement, I would find three animals in my database. But I thought things were supposed to be rolled back, meaning that I would find the database like it was before I ran this script.

Have I misunderstood something? What am I missing? Does the transaction and rollback functions do something else than what I think they should be doing? Is the drop and create statements "breaking" the transaction somehow? What's going on here?


Update: If I move the $db->beginTransaction(); line so the transaction begin only after the table has been created, I get the behavior that I was expecting. So if the third insert statement then failed, I would have an empty table (since it was just recreated) after the transaction was rolled back. Still wondering why it's not working when the drop and create statements are in the transaction though...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜空下最亮的亮点 2024-08-31 18:09:49

查看 PHP 参考手册: PDO::beginTransaction

当在事务中发出数据库定义语言 (DDL) 语句(例如 DROP TABLE 或 CREATE TABLE)时,某些数据库(包括 MySQL)会自动发出隐式 COMMIT。隐式 COMMIT 将阻止您回滚事务边界内的任何其他更改。

这解释了为什么会发生这种情况,这是 MySQL 的限制,而不是 PDO/PHP 的限制。

Check the PHP reference manual: PDO::beginTransaction

Some databases, including MySQL, automatically issue an implicit COMMIT when a database definition language (DDL) statement such as DROP TABLE or CREATE TABLE is issued within a transaction. The implicit COMMIT will prevent you from rolling back any other changes within the transaction boundary.

This explains why this happens, and it's a limitation of MySQL, not of PDO/PHP.

独守阴晴ぅ圆缺 2024-08-31 18:09:49

确保所有表都支持事务。
例如MyISAM不支持。

make sure that all tables support transactions.
for example MyISAM does not supports.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文