2013-06-18 9 views
5

私はCodeIgniterでデータベースにいくつかの行を挿入するための小さなメソッドを実行しています(同じテーブル)。私はどの挿入が(タイトルの配列を返すことによって)トランザクション内で失敗したのか見たいと思います。私のコードは次のとおりです。Codeigniter、トランザクション内のトラッキングエラー

$failure = array(); //the array where we store what failed 
$this->db->trans_start(); 
foreach ($data as $ressourceCsv){ //data is an array of arrays to feed the database 
    $this->ajout_ressource($ressourceCsv); //method to insert (basically, just an insert with active record) 
    if (($this->db->_error_message())!=null) { 
      $failure[] = $ressourceCsv['title']; 
    } 
} 
$this->db->trans_complete(); 
return $failure; 

事実が、私はそれトランザクション(ノーます$ this-> DB->トランス_...)を作成していない場合、それは完璧に動作し、私はいくつかを含む配列を持っているということですタイトル。しかし、このトランザクションでは、配列には最初のエラー以降の各タイトルが含まれています。トランザクションをロールバックする原因となった挿入からタイトルを取得する方法はありますか?

私もして試してみました:

$failure = array(); //the array where we store what failed 
$this->db->trans_start(); 
foreach ($data as $ressourceCsv){ //data is an array of arrays to feed the database 

    if (!$this->ajout_ressource($ressourceCsv)) { //active record insertion return true 
      $failure[] = $ressourceCsv['title']; // if successful 
    } 
} 
$this->db->trans_complete(); 
return $failure; 

答えて

1

私はエラーがトランザクション内で発生したら、あなたはは、任意のより多くのDB改造前ロールバックを行うことができなければならないと考えています。それはあなたが見ている行動を説明するでしょう。最初のエラーが発生すると、トランザクションは「中止」され、ループを続行すると、その後のSQLコマンドもすべて失敗します。これは以下のように示すことができる。エラーが発生した場合、「コミット」は「ロールバック」しているようです

db=# select * from test1; 
id | foo | bar 
----+-----+----- 
(0 rows) 

db=# begin; 
BEGIN 
db=# insert into test1 (foo, bar) values (1, 'One'); 
INSERT 0 1 
db=# insert into test1 (foo, bar) values (Oops); 
ERROR: column "oops" does not exist 
LINE 1: insert into test1 (foo, bar) values (Oops); 
              ^
db=# insert into test1 (foo, bar) values (2, 'Two'); 
ERROR: current transaction is aborted, commands ignored until end of transaction block 
db=# select * from test1; 
ERROR: current transaction is aborted, commands ignored until end of transaction block 
db=# commit; 
ROLLBACK 
ace_db=# select * from test1; 
id | foo | bar 
----+-----+----- 
(0 rows) 

db=# 

は注意(それはタイプミスではなかった。)

またところで:チェックする$this->db->trans_status() === FALSEを使用しますトランザクション中のエラー。

更新:OK

$failure = array(); //the array where we store what failed 
$done = false; 
do { 
    $this->db->trans_begin(); 
    foreach ($data as $key => $ressourceCsv){ //data is an array of arrays to feed the database 
     $this->ajout_ressource($ressourceCsv); //method to insert (basically, just an insert with active record) 
     if ($this->db->trans_status() === false) { // an insert failed 
      $failure[] = $ressourceCsv['title']; // save the failed title 
      unset($data[$key]);     // remove failed insert from data set 
      $this->db->trans_rollback();   // rollback the transaction 
      break;         // retry the insertion 
     } 
    } 
    $done = true;         // completed without failure 
} while (count($data) and ! $done);    // keep going until no data or success 

/* 
* Two options (uncomment one): 
* 1. Commit the successful inserts even if there were failures. 

$this->db->trans_commit(); 

* 2. Commit the successful inserts only if no failures. 

if (count($failure)) { 
    $this->db->trans_rollback(); 
} else { 
    $this->db->trans_commit(); 
} 
*/ 

return $failure; 
+0

ので、私は右のそれを取得した場合、:ここでは、準備が整うまでのインサートが他人に見られないように、トランザクションでそれを行うには、いくつかの(未テスト)のコードですトランザクションの構造が非常にわかりましたので、私が望むように進めることはできません。また、$ this-> db-> trans_status()=== FALSEを使用することはできません。なぜなら、実際にトランザクション文をif文にラップするからです(トランザクションを常に使用しているとは限りません)。私の問題を解決するために、私は最終的に、ロールバックが必要で、$ failure配列が空でない場合、最後にそれらを削除するために成功した挿入のIDを保存しました – Dargor

+0

**あなたが**すべての挿入を一度に行う必要があるあなたがそれを行うことはできますが、失敗した場合にはそれらの挿入物のいずれも見られないというあなたの意図であれば、それを達成することはできません。 "accepted"というブール値の列を持ち、すべての挿入が完了しても失敗した場合にのみTRUEに設定し、他のクエリに 'WHERE accepted = TRUE'句を追加します。 – user9645

+0

必要に応じて、トランザクション内でループを実行する方法を示す更新を追加しました。 – user9645

関連する問題