请记住,MyISAM 表不支持回滚。
我花了一个下午试图找出代码出了什么问题,结果发现代码一直都是正常的。
(PHP 5, PHP 7, PHP 8)
mysqli::rollback -- mysqli_rollback — 回滚当前事务
面向对象风格
过程式风格
回滚数据库的当前事务。
mysql
仅过程式风格:由 mysqli_connect() 或 mysqli_init() 返回的 mysqli 对象。
flags
MYSQLI_TRANS_COR_*
常量的位掩码。
name
如果提供,则执行 ROLLBACK/*name*/
。
如果启用了 mysqli 错误报告 (MYSQLI_REPORT_ERROR
) 并且请求的操作失败,则会生成警告。如果此外将模式设置为 MYSQLI_REPORT_STRICT
,则会抛出 mysqli_sql_exception 而不是警告。
版本 | 描述 |
---|---|
8.0.0 |
name 现在可以为空。 |
参见 mysqli::begin_transaction() 示例。
注意:
此函数不适用于非事务型表类型(如 MyISAM 或 ISAM)。
这是一个解释回滚和提交函数功能的示例。
假设您想确保所有查询都在写入数据库之前无错误执行。
以下是代码
<?php
$all_query_ok=true; // 我们的控制变量
// 我们进行 4 次插入,最后一次会产生错误
// 如果至少有一个查询返回错误,我们更改我们的控制变量
$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; // 重复的 PRIMARY KEY 值
// 现在让我们测试我们的控制变量
$all_query_ok ? $mysqli->commit() : $mysqli->rollback();
$mysqli->close();
?>
希望对您有所帮助!
如果您使用保存点 - 例如 savepoint($foo) - 请注意,尝试使用 rollback(0, $foo) 回滚到保存点,因为这会执行 "ROLLBACK /* $foo */" 而不是 "ROLLBACK TO `$foo`"。
手册页面清楚地说明了这一点,但很容易被忽视。
相反,请使用:$mysqli->query("ROLLBACK TO `$foo`");
关于自动递增 ID 和回滚的说明。
当使用事务并将数据插入包含自动递增 ID 列的表时,即使事务回滚,ID 也会递增。
如果执行了大量回滚,这可能会占用大量 ID。
示例
<?php
$mysqli = new mysqli("localhost", "gugbageri", "gugbageri", "gugbageri");
/* 检查连接 */
if (mysqli_connect_errno()) {
printf("连接失败: %s\n", mysqli_connect_error());
exit();
}
/* 禁用自动提交 */
$mysqli->autocommit(FALSE);
/* 我们只创建一个测试表,包含一个自增主键列和一个内容列 */
$mysqli->query("CREATE TABLE TestTable ( `id_column` INT NOT NULL AUTO_INCREMENT , `content` INT NOT NULL , PRIMARY KEY ( `id_column` )) ENGINE = InnoDB;");
/* 提交新创建的表 */
$mysqli->commit();
/* 我们插入一行 */
$mysqli->query("INSERT INTO TestTable (content) VALUES (99)");
/* 我们提交插入的行 */
$mysqli->commit();
/* 我们再插入三行 */
$mysqli->query("INSERT INTO TestTable (content) VALUES (99)");
$mysqli->query("INSERT INTO TestTable (content) VALUES (99)");
$mysqli->query("INSERT INTO TestTable (content) VALUES (99)");
/* 我们进行回滚 */
$mysqli->rollback();
/* 我们插入一行 */
$mysqli->query("INSERT INTO TestTable (content) VALUES (99)");
/* 我们提交插入的行 */
$mysqli->commit();
if ($result = $mysqli->query("SELECT id_column FROM TestTable")) {
while($row = $result->fetch_row()) {
printf("Id: %d.\n", $row[0]);
}
/* 释放结果 */
$result->close();
}
/* 删除表 TestTable */
$mysqli->query("DROP TABLE TestTable");
$mysqli->close();
?>
这将输出
Id: 1.
Id: 5.
在使用事务时需要注意的是,不应该在事务后立即对同一张表执行普通查询(例如 DELETE)。如果事务回滚,DELETE 将执行并显示受影响的行,但即使 rollback() 命令在 DELETE 查询之前,该行也可能被神奇地重新插入。