我在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-> trans _...),它可以完美地工作,我有一个包含几个标题的数组。但是对于事务,数组包含自第一个错误以来的所有标题。有没有办法从插入中获取导致事务回滚的标题?
我也尝试过:
$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;
答案 0 :(得分:2)
我相信一旦在事务中发生错误,您必须回滚才能再创建任何数据库模块。这可以解释你所看到的行为。在第一个错误之后,事务被“中止”并继续循环,导致每个后续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=#
注意,如果出现错误,“commit”似乎会“回滚”(这不是一个错字。)
同样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;