【问题标题】:Transaction rollback doesn't work事务回滚不起作用
【发布时间】:2011-01-17 21:55:53
【问题描述】:

我已经围绕 PDO 系统制作了一个具有额外功能的数据库包装器(是的,我知道一个包装器周围的包装器,但它只是具有一些额外功能的 PDO)。但是我发现了一个问题。

以下内容并不正常:

<?php
var_dump($db->beginTransaction());

$db->query('
 INSERT INTO test
 (data) VALUES (?)
 ;',
 array(
  'Foo'
 )
);
print_r($db->query('
 SELECT *
 FROM test
 ;'
)->fetchAll());

var_dump($db->rollBack());

print_r($db->query('
 SELECT *
 FROM test
 ;'
)->fetchAll());
?>

var_dump 显示 beginTransaction 和 rollBack 函数返回 true,因此没有错误。

我希望第一个 print_r 调用显示一个包含 N 个项目的数组,第二个调用显示 N-1 个项目。但这不是真的,它们都显示相同数量的项目。

我的 $db->query(, ) 然后 $pdo->prepare()->execute() 什么都不调用(当然还有额外的错误处理)。

所以我认为或者 MySQL 的事务系统不工作,或者 PDO 的实现不工作,或者我发现有问题。

有人知道问题出在哪里吗?

【问题讨论】:

    标签: php mysql pdo transactions


    【解决方案1】:

    检查您的数据库类型是否等于 innoDB。一言以蔽之,您必须检查您的数据库是否支持事务。

    【讨论】:

    • 这就是解决方案。但奇怪的是,为什么在 MyISAM 上使用事务时 pdo 不返回 false (或抛出异常)......奇怪。
    • 您仍然可以使用 MyISAM 进行交易 - 它只是无法回滚。这意味着交易是无操作的。您甚至可以在同一个事务中混合事务性和非事务性表——这只会让人感到困惑。通常(在大多数情况下)你会希望你的所有表都是 innodb。
    【解决方案2】:

    MySQL 不支持 MyISAM 表类型上的事务,不幸的是,这是默认表类型。

    如果你需要事务,你应该切换到 InnoDB 表类型。

    【讨论】:

      【解决方案3】:

      两个可能的问题:

      1. 该表是不支持事务的 MyISAM。使用 InnoDB。

      2. 检查以确保自动提交已关闭。

      http://www.php.net/manual/en/pdo.transactions.php

      【讨论】:

      • 如果我开始显式事务,为什么自动提交应该关闭?
      【解决方案4】:

      我输入此作为答案,因为评论太小,无法包含以下内容:

      PDO 只是各种低级数据库接口库的包装器。如果低级库不抱怨,PDO 也一样。由于 MySQL 支持事务,因此没有事务操作会返回语法错误或其他任何内容。您可以在事务中使用 MyISAM 表,但对它们执行的任何操作都将像自动提交仍然处于活动状态一样完成:

      mysql> create table myisamtable (x int) engine=myisam;
      Query OK, 0 rows affected (0.00 sec)
      
      mysql> create table innodbtable (x int) engine=innodb;
      Query OK, 0 rows affected (0.00 sec)
      
      mysql> start transaction;
      Query OK, 0 rows affected (0.00 sec)
      
      mysql> insert into myisamtable (x) values (1);
      Query OK, 1 row affected (0.00 sec)
      
      mysql> insert into innodbtable (x) values (2);
      Query OK, 1 row affected (0.00 sec)
      
      mysql> rollback;
      Query OK, 0 rows affected, 1 warning (0.00 sec)
      
      mysql> select * from myisamtable;
      +------+
      | x    |
      +------+
      |    1 |
      +------+
      1 row in set (0.00 sec)
      
      mysql> select * from innodbtable;
      Empty set (0.00 sec)
      
      mysql>
      

      如您所见,即使事务处于活动状态,并且在 MyISAM 表上执行了一些操作,也没有引发错误。

      【讨论】:

      • 查询正常,0 行受影响,1 个警告(0.00 秒)也许你可以检索它们是否有任何警告
      • 好点。这是我重做测试插入/回滚后的警告输出:Some non-transactional changed tables couldn't be rolled back
      【解决方案5】:

      发生这种情况的另一个原因是某些类型的 SQL 语句会导致立即自动提交。我有一个大型脚本在一个事务中运行,该事务立即提交并忽略了该事务。我最终发现这是因为任何ALTER TABLE 语句都会立即导致提交发生。

      导致自动提交的语句类型有:

      • 修改表或数据库的任何内容,例如ALTER TABLECREATE TABLE 等。
      • 修改表权限的任何内容,例如ALTER USERSET PASSWORD
      • 锁定该表或启动新事务的任何内容
      • 数据加载语句
      • 管理语句,例如ANALYZE TABLEFLUSHCACHE INDEX
      • 复制控制语句,例如与从属或主有关的任何事情

      更多信息和完整列表可以在这里找到:https://dev.mysql.com/doc/refman/8.0/en/implicit-commit.html

      如果您仅在使用特定脚本时遇到此问题,并且您确定您使用的是 InnoDB,您可能需要查看脚本中是否有任何 SQL 语句与这些匹配。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-23
        • 2015-07-14
        • 2018-05-01
        • 2017-07-18
        • 2017-02-18
        相关资源
        最近更新 更多