【问题标题】:How PDO transaction api works?PDO 事务 API 是如何工作的?
【发布时间】:2016-11-19 05:03:20
【问题描述】:

这是我的代码结构:

// db connection here

try {
    $dbh_conn->beginTransaction();

    $stm = $dbh_conn->prepare("SELECT user_id FROM resend_pass WHERE token = ?");
    $stm->execute(array('value'));
    $num_rows = $stm->fetch(PDO::FETCH_ASSOC);

    if($num_rows) {
        echo 'one'; die;

    } else {
        echo 'two'; die;

    }

    $dbh_conn->commit();

} catch(PDOException $e) {
    $dbh_conn->rollBack();

    echo 'three'; die;

}

该查询何时执行?你知道,我的脚本完全按预期工作。但我想知道怎么做?如您所见,commite() 之前有一个if - else 语句; ifelse 在它们的块中都有 die;。据我所知,这条线永远不会执行:

$dbh_conn->commit();

因为前面有一个 die。但令人惊讶的是,我的代码也能正常工作。以下是所有可能的输出:

  • 如果value 作为标记存在于resend_pass 表中,它将打印one
  • 如果valueresend_pass 表中不作为标记存在,它会打印two
  • 如果有错误,它会打印three(如语法 SQL 错误)

看到了吗?一切都好。但是怎么做? commit() 函数何时执行?在那些dies 之前?

注意:resend_pass的引擎是innoDB

【问题讨论】:

  • 当 php 退出时,它会清理,这意味着它与数据库断开连接。 mysql 将看到这一点并发出回滚以清除任何“垃圾”连接到处乱扔。 die 立即杀死脚本。除非你注册了一个关闭函数,否则你的提交调用将永远没有机会执行。
  • @MarcB "你的提交调用将永远没有机会执行" -- 错误.. 正如我所说,该查询执行并且if($num_rows) { 执行基于该查询的结果。
  • 有什么关系? php 没有时间旅行。仅仅因为在脚本的“未来”某处有一个“die”命令并不意味着 php 将完全拒绝运行该脚本。它逐行运行代码,完全按照代码所说的去做。它运行您的查询。它获取结果。它测试结果,然后它可能会die.
  • @MarcB 我只是想了解,我的脚本结构好吗?还是我应该改变它的结构?
  • 按原样,没关系,尽管您可能不想依赖 php/mysql 在清理情况下进行回滚。也许由于某种原因,oracle 会在未来的某个 mysql 版本中反转逻辑并在关闭时提交未完成的事务。不明白为什么,这会非常愚蠢,但无论如何,逻辑从来都不是与 oracle 相同的句子。

标签: php mysql pdo transactions


【解决方案1】:

在调用execute() 时执行查询(注意query() 调用execute())。

如果查询更改了支持事务的表中的数据,则在释放 PDO 对象时回滚更改,因为对象超出范围或脚本终止并清理。这是由于 PDO 代码,而不是 MySQL。

如果查询更改了不支持事务的表(例如 MyISAM 表)中的数据,则更改在执行时是永久性的,并且无法回滚。

有一些SQL statements that perform an implicit commit。即使您的脚本在调用 commit() 之前死掉,它们也会在执行后立即变为永久性。

正如@MarcB 提到的,您的示例显示了一个只读的SELECT 语句。如果你使用INSERT/UPDATE/DELETE,测试行为会更容易。

【讨论】:

  • 那么我目前的结构还好吗?
  • 是的,没关系。如果您的脚本调用die(),事务将被回滚。
  • 我有一个非常相似的问题。如果您有空闲时间,请看一下stackoverflow.com/questions/38579529/…
猜你喜欢
  • 2016-04-13
  • 2017-05-14
  • 2012-07-08
  • 1970-01-01
  • 2015-05-31
  • 1970-01-01
  • 1970-01-01
  • 2015-11-23
  • 1970-01-01
相关资源
最近更新 更多