2015-08-21 55 views
0

我正在努力實施PHP和MySQL事務。該腳本通過阻塞redisqueue接收SQL語句以及一些綁定參數。一切都傳遞給一個函數'do_transaction',它跟蹤收到的語句的數量。PHP PDO未執行MySQL事務

我已經調試PDO的聲明(已被處理後)與PdoDebugger和輸出是正確的:

UPDATE bla SET processed = 1, severity_ou1 = 'low', 
severity_ou2 = 'low', severity_ou3 = 'low', severity_ou4 = 'low', 
severity_ou5 = 'low', saved = '1', hname = '1', sname = '1', if = '1', 
v = '1', translated = 'blablabla.', filtered = 1, repeated = '1', 
excessed = '1', eventfilterid = '212', building = '1', floor = '1' 
WHERE id = '121614624' 
global $batchcount; 
$batchcount = 1; 

while(true){ 
    $redis = new Redis(); 
    $redis->connect('xxx', xxx); 
    $sqlbatch = $redis->blpop('xxx:xxx:sqlfiltermatch', 0); 

    // blpop returns array: 0 has key, 1 has data. 
    if(is_array($sqlbatch)){ 
     if(isJson($sqlbatch[1])){ 
      $batchstatements = array(); 
      $batchstatements[] = json_decode($sqlbatch[1], true); 
      // Get statement and bindparams. 
      $sqlstatement = $batchstatements[0]['statement']; 
      $bindparams = $batchstatements[0]['bindparams']; 
      // Replace empty bindparams. 
      foreach($bindparams as $column => $value){ 
       if(is_null($value)){ $bindparams[$column] = '1'; } 
       if(empty($value)){ $bindparams[$column] = '1'; } 
      } 
     } 
     $batchcount++; 
     do_transaction($sqlstatement, $bindparams, $batchcount); 
    } 
} 

function do_transaction($sqlstatement, $bindparams){ 
    global $batchcount; 
    if($batchcount >= 4){ 
     try { 
      // Setup DB 
      $db = new PDO('mysql:host=xxx;dbname=xxx;charset=utf8', 'xxx', 'xxx', array(PDO::ATTR_PERSISTENT => true, PDO::ATTR_AUTOCOMMIT => FALSE, PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING)); 
      echo $db->getAttribute(PDO::ATTR_AUTOCOMMIT)."\n\n"; 
      $db->beginTransaction(); 
      $stmt = $db->prepare($sqlstatement); 

      // Setup bindparams. 
      foreach($bindparams as $column => $value){ 
       $stmt->bindParam(":$column", $value); 
      } 
      $stmt->execute() or die(print_r($stmt->errorInfo(), true)); 
      echo PdoDebugger::show($sqlstatement, $bindparams)."\n"; 
      $db->commit(); 

     } catch(PDOExecption $e){ 
      //$db->rollback(); 
      print_r("ERROR"); exit;    
     } 
     $batchcount = 0; 
    } 

    $batchcount++; 
} 

我確信,AUTOCOMMIT = FALSE。 「do_transaction」中哪裏出錯?

+0

也許在您的查詢中有錯誤,SQL錯誤與PDO_EXCEPTION不同,所以如果[插入錯誤]在這裏,語法錯誤,鑄造錯誤,無論如何,那麼即使提交,事務也不會完成。 – Lucas

回答

1

以這種方式使用交易沒有意義。 所以,只是讓他們一個人。

function do_query($db, $sqlstatement, $bindparams){ 
    $stmt = $db->prepare($sqlstatement); 
    $stmt->execute($bindparams); 
    return $stmt; 
} 

是您實際需要的所有代碼。

使用這種方式

$db = new PDO('mysql:host=xxx;dbname=xxx;charset=utf8', 'xxx', 'xxx', 
    array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION) 
); 
while(true){ 
    // whatever redis code goes here 
    do_query($db, $sqlstatement, $bindparams); 
} 

諾塔好處:如果你想使你的刀片快,你應該問標題爲「如何使插入更快」,也沒有「我的交易不工作」的問題。

但您的插入交易的想法也是錯誤的。
單個事務(根據業務邏輯)必須儘快寫入數據庫,而不會干擾其他事務。意味着你不應該在單個數據庫transacion內耦合不同的業務邏輯事務。因爲單個業務邏輯事務中的錯誤會破壞整個批次。所以 - 只要分開寫。

+0

我的目標是使用redisqueue快速接收交易,並將它們合併爲單個交易。我認爲這批次對於大量報表而言仍然比單筆交易更快? – driesken

+0

感謝您編寫交易的想法!我會認爲我會堅持單一交易。 – driesken