2013-06-18 39 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; 

的事实是,如果我不让它交易(无$这个 - > 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 MODS回退可。这将解释你所看到的行为。第一个错误之后,事务被“中止”,并且继续循环,导致每个后续的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=# 

注意似乎“承诺”做了“回退”,如果有错误(这不是一个错字。)

而且BTW:使用$this->db->trans_status() === FALSE检查这可以说明如下在交易过程中发生错误。

更新:这里的一些(未经测试)的代码做一个交易,以使刀片不被别人看到,直到你准备:

$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语句中(我并不总是使用事务)。为了解决我的问题,我终于存储了成功插入的ID,最后删除它们,如果我想要回滚并且$ failure数组不是空的 – Dargor

+0

我想如果你必须**一次完成所有的插入操作任何失败,那么你可以做到这一点,但如果你的意图是没有人会看到任何插入,如果一些失败,那么你不能这样做。你可以有一个名为“accepted”的布尔列,并且只有在所有插入完成并且没有失败之后才将其设置为TRUE,并向其他查询添加一个WHERE accepted = TRUE'子句。 – user9645

+0

我添加了更新以显示如何在事务内执行循环(如果需要)。 – user9645