Php mysqli::如何提交&;mysqli::回滚工作?

Php mysqli::如何提交&;mysqli::回滚工作?,php,mysql,mysqli,commit,rollback,Php,Mysql,Mysqli,Commit,Rollback,我已经阅读了在线php手册,但我仍然不确定这两个函数的工作方式:mysqli::commit和mysqli::rollback 我要做的第一件事是: $mysqli->autocommit(FALSE); 然后我提出一些疑问: $mysqli->query("..."); $mysqli->query("..."); $mysqli->query("..."); 然后,我通过执行以下操作提交由这3个查询组成的事务: $mysqli->commit(); 但是在

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

我要做的第一件事是:

$mysqli->autocommit(FALSE);
然后我提出一些疑问:

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

$mysqli->commit();
但是在不幸的情况下,其中一个查询不起作用,那么这三个查询是全部被取消了,还是我必须自己调用回滚?我希望所有3个查询都是原子的,并且只被视为一个查询。如果一个查询失败,那么所有3个查询都应该失败并且没有效果

我这样问是因为我在手册页面上看到的评论: 如果其中一个查询失败,用户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(); 
?>
如下所述:

InnoDB中的错误处理并不总是与SQL标准中指定的相同。根据标准,SQL语句中的任何错误都会导致该语句回滚
InnoDB
有时只回滚语句的一部分或整个事务。以下项目描述了
InnoDB
如何执行错误处理:

  • 如果在中耗尽了文件空间,则会出现MySQL
    表已满的错误,并且
    InnoDB
    回滚SQL语句

  • 事务导致整个数据库
    InnoDB
    。发生这种情况时,请重试整个事务

    锁定等待超时导致
    InnoDB
    仅回滚等待锁定并遇到超时的单个语句。(若要回滚整个事务,请使用选项启动服务器。)如果使用当前行为,请重试该语句;如果使用,请重试整个事务

    死锁和锁等待超时在繁忙的服务器上都是正常的,应用程序必须意识到它们可能发生,并通过重试来处理它们。您可以通过在事务期间对数据进行第一次更改和提交之间尽可能少的工作来降低这种可能性,因此锁的保留时间尽可能短,行数尽可能少。有时,在不同的事务之间拆分工作可能是实用且有用的

    当由于死锁或锁等待超时而发生事务回滚时,它将取消事务中语句的效果。但是,如果start transaction语句是or语句,rollback不会取消该语句。进一步的SQL语句将成为事务的一部分,直到出现导致隐式提交的SQL语句或某些SQL语句

  • 如果未在语句中指定
    IGNORE
    选项,则重复键错误会回滚SQL语句

  • 行过长错误
    回滚SQL语句

  • 其他错误大多由MySQL代码层检测(在
    InnoDB
    存储引擎级别之上),它们回滚相应的SQL语句。锁不会在单个SQL语句的回滚中释放

我认为这段代码是错误的,因为如果任何查询失败 $all\u query\u 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\u INCREMENT
-值因错误的查询而增加

因此,您必须检查每个
查询
-调用的结果,如果其中一个调用失败,请调用
回滚
以撤消其他成功的查询。因此,PHP手册中的Lorenzo代码是有意义的


迫使MySQL回滚事务的唯一错误是“事务死锁”(这是InnoDB特有的,其他存储引擎可能会以不同的方式处理这些错误)

开始工作区在哪里?您知道什么是自动提交吗?如果您将sql语句包装在a侧的
开始事务
结束
块中,则此功能有效。因此,如果您的任何语句在事务块内失败,它将回滚事务。@N.B.我想我知道什么是自动提交:如果它打开,则我调用的每个查询都将被数据库即时处理;如果它关闭,则只有在$mysqli->commit()时,查询才会发送到数据库;调用。@Ariel-autocommit是InnoDB的工作模式。
commit
是要求操作系统验证永久存储设备(本例中为硬盘驱动器)是否写下了信息,以及该信息是否不在任何内存缓冲区中。这是一个耗资巨大的信息/操作,它使用了1个输入输出操作。当自动提交打开时,发送到DB的每个查询都将使用1 I/O抛出异常/如果失败则引发错误。关闭自动提交对事务基本上没有意义。您需要一个
开始工作
块,而不是关闭自动提交。@N.B.:
开始工作
(及其推荐的标准化替代方法
启动事务
)只需为一个事务隐式关闭自动提交。显式关闭自动提交即使在事务结束后也会将其关闭。就这个问题而言,没有什么区别。太好了!非常感谢。这正是我想知道的。