2016-07-15 59 views
1

这里是我的代码结构:PDO事务API如何工作?

// 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。但令人惊讶的是我的代码也可以工作。这里是所有可能的输出:

  • 它打印one如果value存在作为resend_pass表的令牌。
  • 如果valueresend_pass表中不存在作为令牌,则它将打印two
  • 它打印three如果有错误(如语法SQL错误)

看到了吗?一切都好。但是如何?当commit()函数执行时?在那之前die

注:resend_pass发动机是InnoDB的

+0

当php退出时,它会清理,这意味着它从数据库中断开。 mysql会看到并发出回滚来清除连接周围的任何“垃圾”。 '死'立即杀死剧本。除非你注册了关闭函数,否则你的提交调用永远不会有机会执行。 –

+0

@MarcB *“您的提交调用永远不会得到执行的机会”* - 错误。正如我所说,该查询执行并且“if($ num_rows){”根据该查询的结果执行。 –

+0

这有什么关系? PHP不会时间旅行。仅仅因为在脚本的“未来”某处有一个“死亡”命令并不意味着php将拒绝运行该脚本。它一行一行地运行代码,完全按照代码说的去做。它运行你的查询。它获取结果。它会测试结果,那么它可能会“死亡”。 –

回答

1

调用​​时会执行查询(请注意,query()调用​​)。

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

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

还有一些SQL statements that perform an implicit commit。即使您的剧本在致电commit()之前死亡,它们将在执行后立即永久生效。

正如@MarcB所述,您的示例显示只读SELECT声明。如果使用INSERT/UPDATE/DELETE,则测试行为会更容易。

+0

所以我目前的结构很好? –

+0

是的,没关系。如果你的脚本调用'die()',事务将被回滚。 –

+0

我有一个非常类似的问题。请如果你有一些空闲时间看看它http://stackoverflow.com/questions/38579529/how-my-script-rollbacks-the-queries-before-executing-rollback-function – stack