PHP PDO - 没有活动事务

时间:2016-12-30 08:22:15

标签: php mysql pdo transactions

我在php脚本中遇到问题。如果其中至少有一个失败,我想进行多次查询并能够全部回忆它们。您可以在下面找到我正在使用的脚本的简单示例:

$tags_input = array(6,4,5);
$conn = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8',  
DB_USER, DB_PASSW, array(  
    PDO::ATTR_EMULATE_PREPARES => false,  
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));

    $conn->beginTransaction();

    $sql = "INSERT INTO projects (id, pr_id, enabled) VALUES ( :val0, :val1, :val2)";
    $stmt = $conn->prepare($sql);  
    if(count($tags_input)>0){
            for($i = 0;$i<count($tags_input);$i++){
                    $stmt->bindValue(':val0', 57); 
                    $stmt->bindValue(':val1', $tags_input[$i]); 
                    $stmt->bindValue(':val2', 'Y'); 
                    $result = $stmt->execute();

            }

    }

    $res1 = $conn->commit();
    $conn->rollBack();

现在,此示例生成错误:

  

未捕获的异常&#39; PDOException&#39;有消息&#39;没有活动   交易&#39;

如果我删除了行$conn->rollBack();,则错误消失。因此,我无法理解为什么pdo对象无法看到开放式事务(begintransactioncommit不会产生任何错误)。我也尝试将rollBack()放在交易中,但没有任何区别。我仍然收到错误&#39;没有活动的交易&#39;。

我在InnoDB上运行PHP 5.6和Mysql表。

2 个答案:

答案 0 :(得分:3)

将您的交易代码包含在try-catch语句中。

//try {
$tags_input = array(6,4,5);
$conn = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8',  
DB_USER, DB_PASSW, array(  
    PDO::ATTR_EMULATE_PREPARES => false,  
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
} catch (Exception $e) {
  die("Unable to connect: " . $e->getMessage());
}    
try {  
    $conn->beginTransaction();   
    $sql = "INSERT INTO projects (id, pr_id, enabled) VALUES ( :val0, :val1, :val2)";
    $stmt = $conn->prepare($sql);  
    if(count($tags_input)>0){
            for($i = 0;$i<count($tags_input);$i++){
                    $stmt->bindValue(':val0', 57); 
                    $stmt->bindValue(':val1', $tags_input[$i]); 
                    $stmt->bindValue(':val2', 'Y'); 
                    $result = $stmt->execute();
            }
    }
$res1 = $conn->commit();    
} catch (Exception $e) {
  $conn->rollBack();
  echo "Failed: " . $e->getMessage();
}

修改

Richard作为评论提供了对答案的真正基础和直接的解释。

  

您收到错误的原因是因为您在交易已经关闭时尝试关闭该交易。 beginTransaction 会打开一个,而 rollBack 提交会关闭它。您必须避免对单个 beginTransaction 语句执行BOTH操作(即提交/回滚),否则您将收到错误。上面的try / catch代码确保只执行一个结束语句。

答案 1 :(得分:2)

彼得和理查兹的答案已经是正确的,但是交易结构中的代码中有一个小错误(我无法添加评论)。

$connection->beginTransaction()必须在try - catch块之外。当您在beginTransaction() - 块中启动try并且您的数据库操作引发异常时,catch - 阻止对活动事务中的某些内容不了解。所以,你得到同样的错误:

  

&#34;没有活动的交易&#34;。

所以结构也应如此:

  1. 获取连接。
  2. 使用$connection->beginTransaction()
  3. 启动交易
  4. 打开try - catch阻止。
  5. try - 块在DB操作后包含$connection->commit()

    catch - 块在抛出异常之前包含$connection->rollback()

    所以你的代码应该是这样的:

    $tags_input = array(6,4,5);
    $conn = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8',  
    DB_USER, DB_PASSW, array(  
        PDO::ATTR_EMULATE_PREPARES => false,  
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
    } catch (Exception $e) {
      die("Unable to connect: " . $e->getMessage());
    }    
    //Begin Transaction
    $conn->beginTransaction();   
    try {  
        $sql = "INSERT INTO projects (id, pr_id, enabled) VALUES ( :val0, :val1, :val2)";
        $stmt = $conn->prepare($sql);  
        if(count($tags_input)>0){
                for($i = 0;$i<count($tags_input);$i++){
                        $stmt->bindValue(':val0', 57); 
                        $stmt->bindValue(':val1', $tags_input[$i]); 
                        $stmt->bindValue(':val2', 'Y'); 
                        $result = $stmt->execute();
                }
        }
    $res1 = $conn->commit();    
    } catch (Exception $e) {
      $conn->rollBack();
      echo "Failed: " . $e->getMessage();
    }