Codeigniter,事务中的错误跟踪

Posted

技术标签:

【中文标题】Codeigniter,事务中的错误跟踪【英文标题】:Codeigniter, error tracking in transaction 【发布时间】:2013-06-14 16:02:06 【问题描述】:

我正在 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;

【问题讨论】:

【参考方案1】:

我相信一旦事务中发生错误,您必须回滚,然后才能制作更多的数据库模块。这将解释您所看到的行为。在第一个错误之后,事务被“中止”并且您继续循环,导致每个后续 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 在交易过程中检查错误。

更新:这里有一些(未经测试的)代码可以在事务中执行此操作,以便在您准备好之前其他人看不到插入:

$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;

【讨论】:

好的,所以如果我做对了,交易的结构本身就不允许我按照我的意愿进行。我也不能使用 $this->db->trans_status() === FALSE 因为我实际上将事务行包装在 if 语句中(我并不总是使用事务)。为了解决我的问题,如果我想要回滚并且$failure数组不为空,我最后存储了成功插入的id以便最后删除它们 我想如果您必须一次完成所有插入而不考虑任何失败,那么您可以这样做,但如果您的意图是没有其他人会看到其中任何一个如果有些失败则插入,那么您无法以这种方式完成它。您可以有一个名为“accepted”的布尔列,并仅在所有插入完成且没有失败后将其设置为 TRUE - 并将 WHERE accepted = TRUE 子句添加到您的其他查询中。 我添加了更新来展示如何在事务中执行循环。

以上是关于Codeigniter,事务中的错误跟踪的主要内容,如果未能解决你的问题,请参考以下文章

codeigniter,从不直接调用视图,有人可以解释一下

codeigniter 4 设置会话变量 $session = \Config\Services::session();全球

要使用codeigniter框架还是标准的php? [关闭]

使用 Codeigniter 进行数据表服务器端处理

如何使用 codeigniter 中的事务进行基于数据更改的提交和回滚?

Codeigniter 事务测试失败