我已经阅读了在线php手册,但仍然不确定这两个函数的工作方式:mysqli::commit和mysqli::rollback。
我要做的第一件事是:

$mysqli->autocommit(FALSE);

然后我提出一些问题:
$mysqli->query("...");
$mysqli->query("...");
$mysqli->query("...");

然后,我通过执行以下操作提交由这3个查询组成的事务:
$mysqli->commit();

但不幸的是,在其中一个查询不起作用的情况下,这3个查询是否都被取消,或者我必须自己调用回滚?我希望所有3个查询都是原子的,并且只被视为一个查询。如果一个查询失败,那么所有3个查询都应该失败,并且没有任何效果。
我这么问是因为我在手册上看到的评论:http://php.net/manual/en/mysqli.commit.php
如果其中一个查询失败,用户lorenzo将调用回滚。
如果3个查询是原子的,那么回滚有什么好处?我不明白。
编辑:这是我怀疑的代码示例:
<?php
$all_query_ok=true; // our control variable
$mysqli->autocommit(false);
//we make 4 inserts, the last one generates an error
//if at least one query returns an error we change our control variable
$mysqli->query("INSERT INTO myCity (id) VALUES (100)") ? null : $all_query_ok=false;
$mysqli->query("INSERT INTO myCity (id) VALUES (200)") ? null : $all_query_ok=false;
$mysqli->query("INSERT INTO myCity (id) VALUES (300)") ? null : $all_query_ok=false;
$mysqli->query("INSERT INTO myCity (id) VALUES (100)") ? null : $all_query_ok=false; //duplicated PRIMARY KEY VALUE

//now let's test our control variable
$all_query_ok ? $mysqli->commit() : $mysqli->rollback();

$mysqli->close();
?>

我认为这段代码是错误的,因为如果任何查询失败并且$all_query_ok==false,则不需要执行回滚,因为事务未被处理。我说得对吗?

最佳答案

我认为这段代码是错误的,因为如果任何查询失败并且
$all_query_ok==false,则不需要执行回滚,因为
未处理事务。我说得对吗?
不,如果一个sql语句失败,事务就不会跟踪。
如果一个sql语句失败,则回滚该语句(如@eggyal的答案中所述),但事务仍处于打开状态。如果现在调用commit,则不会回滚成功的语句,而只是将“损坏的”数据插入数据库。你可以很容易地重现:

m> CREATE TABLE transtest (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
 name VARCHAR(100) NOT NULL DEFAULT '',
 CONSTRAINT UNIQUE KEY `uq_transtest_name` (name)) ENGINE=InnoDB;
Query OK, 0 rows affected (0.07 sec)

m> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

m> INSERT INTO transtest (name) VALUE ('foo');
Query OK, 1 row affected (0.00 sec)

m> INSERT INTO transtest (name) VALUE ('foo');
ERROR 1062 (23000): Duplicate entry 'foo' for key 'uq_transtest_name'

m> INSERT INTO transtest (name) VALUE ('bar');
Query OK, 1 row affected (0.00 sec)

m> COMMIT;
Query OK, 0 rows affected (0.02 sec)

m> SELECT * FROM transtest;
+----+------+
| id | name |
+----+------+
|  3 | bar  |
|  1 | foo  |
+----+------+
2 rows in set (0.00 sec)

您可以看到,虽然第二条sql语句失败了,但是“foo”和“bar”的插入是成功的—您甚至可以看到,错误的查询增加了AUTO_INCREMENT-值。
因此,您必须检查每个query-调用的结果,如果一个调用失败,则调用rollback以撤消其他成功的查询。所以lorenzo在php手册中的代码是有意义的。
唯一迫使mysql回滚事务的错误是“事务死锁”(这是innodb特有的,其他存储引擎可能会以不同的方式处理这些错误)。

07-24 09:45
查看更多