我发现自己对 MySQLi 在遇到错误查询时处理保存点的方式感到有点困惑。
这是我遇到的问题的 MRE:
$mysqli = new mysqli($_HOST, $_USER, $_PASS, $_DB_NAME); // replace with credentials
$mysqli->begin_transaction();
$mysqli->savepoint("SP1"); // savepoint() method - I get the same problem when using the SAVEPOINT query
$mysqli->query("INSERT INTO Users (Username, FavouriteColour) VALUES ('Alice', 'Red');"); // valid query
$mysqli->savepoint("SP2");
$mysqli->query("INSERT INTO Users (Username, FavouriteColour) VALUES ('Bob', 'Green');"); // another valid query
$mysqli->savepoint("SP3");
$mysqli->query("INSERT INTO Users (Username, FavouriteColour) VALUES ('Charlie', 'Blue');"); // third valid query
$mysqli->query("CREATE TABLE Users (ID INT AUTO_INCREMENT NOT NULL PRIMARY KEY, Username VARCHAR(255), FavouriteColour VARCHAR(64));"); // obviously invalid query - Users already exists.
$mysqli->query("ROLLBACK TO SAVEPOINT SP2"); // Time to rollback! I use the ROLLBACK query since the rollback($name) method doesn't actually rollback to the savepoint with the name parameter.
$mysqli->commit(); // Commit the transaction.
在这个小事务之后,最后两个添加应该已经回滚了,对吧?当交易过程中“没有”无效查询时,肯定会发生这种情况。应该添加爱丽丝,但不应该添加鲍勃和查理。 事务中间出现的(不是语法上的,而是逻辑上的)无效查询显然似乎完全让 MySQLi 崩溃了。 MySQLi 不是保留事务并让我回滚到我想要的状态,也不是撤消整个事务(这是可以理解的,因为其中存在错误),而是保留整个事务
但删除所有保存点。当我尝试回滚到上述三个保存点中的任何一个时,它会出现“保存点不存在”错误。结果,所有三个有效查询都被提交(即使我最后没有手动提交它们,即使我尝试回滚最后两个查询,如上所述)。 除非我在这里做错了什么,MySQLi 决定处理错误的最佳方法是继续执行所有查询,但删除所有保存点(它们是...处理错误的方式)。如果我自己或 MySQLi 在这里很愚蠢,请告诉我!
注意 - 当事务中没有无效查询时,保存点/回滚工作得很好。第一个查询被执行,然后是第二个和第三个,但是回滚到 SP2 取消了第二个和第三个查询,因此只提交了第一个查询。
SAVEPOINT
是交易的一部分。提交事务后,保存点将被删除。