我已经在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-&gt;查询(&lt; sql&gt;,&lt; values&gt;)之后不再调用$ pdo-&gt; prepare(&lt; sql&gt;) - &gt; execute(&lt; values&gt; )(有额外的错误处理)。
所以我认为或MySQL的交易系统不起作用,或者PDO的实现不起作用或者我看错了。
有人知道问题是什么吗?
答案 0 :(得分:14)
检查您的数据库类型是否等于innoDB。总之,您必须检查数据库是否支持事务。
答案 1 :(得分:4)
两个可能的问题:
该表是MyISAM,不支持事务。使用InnoDB。
检查以确保自动提交为OFF。
答案 2 :(得分:3)
我正在输入这个作为答案,因为评论很小以包含以下内容:
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表上执行了某些操作,也不会引发任何错误。
答案 3 :(得分:2)
MySQL不支持MyISAM表类型的事务,遗憾的是它是默认的表类型。
如果您需要交易,则应切换到InnoDB表类型。
答案 4 :(得分:0)
发生这种情况的另一个原因是某些类型的SQL语句会导致立即自动提交。我有一个很大的脚本运行在一个事务中,该事务立即被提交并忽略了该事务。我最终发现这是因为任何ALTER TABLE
语句都会立即导致一次提交。
导致自动提交的语句类型为:
ALTER TABLE
,CREATE TABLE
等。ALTER USER
或SET PASSWORD
ANALYZE TABLE
,FLUSH
或CACHE INDEX
更多信息和完整列表可以在这里找到:https://dev.mysql.com/doc/refman/8.0/en/implicit-commit.html
如果仅在特定脚本中遇到此问题,并且确定使用的是InnoDB,则可能要查看脚本中是否有任何SQL语句与之匹配。