PHP PDO - There is no active transaction

use*_*756 7 php mysql pdo transactions

I am having problem with transactions in php script. I would like to make multiply queries and be able to recall them all, if at least one of them fails. Below you can find a simple example of the script I am using:

$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();
Run Code Online (Sandbox Code Playgroud)

Now, this example generates an error:

Uncaught exception 'PDOException' with message 'There is no active transaction'

If I erase the line $conn->rollBack();, the error disappears. Therefore I cannot understand, why pdo object can't see open transaction (begintransaction and commit do not generate any errors). I also tried putting rollBack() inside the transaction, but made no difference. I was still getting an error 'There is no active transaction'.

I am running PHP 5.6 and Mysql tables on InnoDB.

小智 7

将您的事务代码包装在 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();
}
Run Code Online (Sandbox Code Playgroud)

编辑

理查德作为评论提供了对答案的一个非常有根据和直接的解释。

出现错误的原因是因为您试图关闭已经关闭的事务。beginTransaction打开一个,然后回滚提交关闭它。您必须避免对单个beginTransaction语句执行 BOTH 操作,即提交/回滚,否则会出错。上面的 try/catch 代码确保只执行一个结束语句。

  • 补充一点,您出现错误的原因是因为您试图在交易已经关闭时关闭它。“beginTransaction”打开一个,“rollBack”或“commit”关闭它。您必须避免对单个“beginTransaction”语句执行提交/回滚,否则您将收到错误消息。上面的 try/catch 代码确保只执行 1 个“关闭”语句。 (2认同)

小智 5

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

$connection->beginTransaction()必须之外的try-catch块。当您beginTransaction()try-block 中启动并且您的数据库操作抛出异常时,catch-block 不知道活动事务中的某些内容。所以,你会得到同样的错误:

“没有活跃的交易”。

所以结构也应该是:

  1. 获取连接。
  2. 开始交易 $connection->beginTransaction()
  3. 打开try-catch块。

try嵌段包含$connection->commit()DB操作后。

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();
}
Run Code Online (Sandbox Code Playgroud)