代码之家  ›  专栏  ›  技术社区  ›  Brian Smooner

MySQLi在事务出错时删除保存点(并且仅删除保存点)?

  •  1
  • Brian Smooner  · 技术社区  · 1 年前

    当遇到错误查询时,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会取消第二和第三次查询,因此只提交第一次查询。

    1 回复  |  直到 1 年前
        1
  •  0
  •   Dharman Aman Gojariya    1 年前

    事务是由DDL语句隐式提交的。A. SAVEPOINT 是交易的一部分。提交事务时,保存点将被删除。

    如果执行COMMIT或不命名保存点的ROLLBACK,则会删除当前事务的所有保存点。

    事务在尝试DDL语句之前提交。因此,是否 CREATE TABLE 查询成功或失败。无论哪种方式,保存点都将被删除。

    推荐文章