PHP PDO对象如何确定它是否已经存在于MySQL事务中?

时间:2010-09-01 00:58:28

标签: php mysql pdo

我有两个复杂的PHP对象,每个对象都有几个MySQL表中的数据。

有时,我只需要从数据库中删除一个对象A,这需要3个SQL语句。

有时候,我需要从数据库中删除一个对象B,这需要4个SQL语句,需要找到并删除对象B拥有的所有对象A.

因此在函数delete_A()中,我在事务中执行这些语句。在delete_B()函数内部,我想运行一个覆盖delete_A()内部活动的大型事务。如果删除B的整个原子都失败了,我需要在回滚中恢复它的所有A。

如何更新delete_A()的定义以仅打开新的交易如果尚未运行更大的交易。

我希望能够做到这一点,但autocommit

似乎没有改变beginTransaction()属性
function delete_A($a){
  global $pdo;
  $already_in_transaction = !$pdo->getAttribute(PDO::ATTR_AUTOCOMMIT);
  if(!$already_in_transaction){
    $pdo->beginTransaction();
  }

  //Delete the A

  if(!$already_in_transaction){
    $pdo->commit();
  }
}
function delete_B($b){
  global $pdo;
  $pdo->beginTransaction();
  foreach($list_of_As as $a){
    delete_A($a);
  }
  $pdo->commit();
}

3 个答案:

答案 0 :(得分:7)

PDO::ATTR_AUTOCOMMIT不是指标属性,它是一个控制属性。它控制SQL语句在完成时是否隐式提交。

如果您没有正在进行的事务,则可以调用PDO::inTransaction()返回0,如果您有未完成的事务需要提交或回滚,则可以调用1。但是,此功能没有记录,因此很难说它是否可以安全地依赖它存在于所有未来版本的PDO中。

我建议PHP开发人员不要尝试管理函数或类范围内的事务。您应该在应用程序的顶层管理事务。

另见:

答案 1 :(得分:2)

我最后只使用->beginTransaction()引发的异常来判断我是否在事务中,并使用它来决定是否在内部循环中提交。所以delete_A()最终看起来像:

function delete_A($a){
  global $pdo;
  try {
    $pdo->beginTransaction();
  } catch (PDOException $e) {
    $already_in_transaction = true;
  }

  //Delete the A

  if(!$already_in_transaction){
    $pdo->commit();
  }
}

delete_B()无需修改就可以使用。

答案 2 :(得分:1)

一种方法是创建自己的PDOConnect类,该类具有$hasTransaction变量。那你就检查一下。可以在php.net上的beginTransaction函数的注释中找到一个示例http://www.php.net/manual/en/pdo.begintransaction.php#81022

那是我的偏好。虽然这个例子需要调整和打扮等,但应该是一个良好的基础。

旁注请记住,您的表应该是INNODB,以便交易正常运行。因为您需要在INNODB中处理交易,所以您应该采用prodigitals的建议并使用外键约束。