CodeIgniter中的事务无法回滚

4

我正在处理事务,但在这个代码中遇到了一些问题。 我没有提交事务,但它仍将数据插入到了我的数据库中。

$this->db->trans_begin();
$this->db->insert('tblorder',$data);
$orderid=$this->db->insert_id();
foreach ($orderItemList as $orderItemList) {
    $orderitem = array('orderid' =>$orderid ,'productid' =>$orderItemList->productid ,'amount' =>$orderItemList->amount);
    $this->db->insert('tblorderitem',$orderitem);
}
$this->db->trans_complete();

if ($this->db->trans_status() == 1) {
    $this->db->trans_rollback();
    return "true";
} else {
    $this->db->trans_commit();
    return "false";
}

我回滚了事务,但是所有数据又重新插入到了我的数据库中。这可能是什么问题呢?我无法理解。

6个回答

8

不要使用 $this->db->trans_complete();

根据文档,请勿使用该函数。

$this->db->trans_begin();

$this->db->query('AN SQL QUERY...');
$this->db->query('ANOTHER QUERY...');
$this->db->query('AND YET ANOTHER QUERY...');

if ($this->db->trans_status() === FALSE)
{
        $this->db->trans_rollback();
}
else
{
        $this->db->trans_commit();
}

2

按照以下步骤进行操作。如果您想了解有关事务的更多信息,请查看我在另一个问题上的回答。这将帮助您清楚地了解事务。

$this->db->trans_begin();

$this->db->insert('tblorder',$data);
$orderid=$this->db->insert_id();

$orderitem = array();

foreach ($orderItemList as $orderItemList) 
{
    $orderitem[] = array('orderid' =>$orderid ,'productid' =>$orderItemList->productid ,'amount' =>$orderItemList->amount);
}

$this->db->insert_batch('tblorderitem', $orderitem); 

$this->db->trans_complete();

if ($this->db->trans_status() === FALSE) 
{
    $this->db->trans_rollback();
    return FALSE;
} 
else 
{
    $this->db->trans_commit();
    return TRUE;
}

2
您编写的代码与自动事务编写方式几乎相同,只是没有那么好。我的建议是:不要试图比CodeIgniter更聪明,使用“自动”模式进行事务处理。这样,如果需要回滚,则会为您处理。我已经使用自动事务模式重新编写了您的代码。我还从$orderItemList中收集数据,以便可以使用批处理进行插入,而不是在循环中重复调用db->insert
$this->db->trans_start();
$this->db->insert('tblorder', $data);
$orderid = $this->db->insert_id();
foreach($orderItemList as $orderItem)
{
    $orderedItems[] = [
      'orderid' => $orderid,
      'productid' => $orderItem->productid,
      'amount' => $orderItem->amount
    ];
}
if(isset($orderedItems))
{
    $this->db->insert_batch('tblorderitem', $orderedItems);
}
$this->db->trans_complete();
$this->db->trans_status();

2

答案已更新!

我必须告诉你,CodeIgniter的配置默认情况下会自动提交所有事务。

如果出于任何原因,您想禁用此功能,您需要使用以下代码:

$this->db->trans_off();    

之前的

$this->db->begin();

Said that, so when you use

$this->db->trans_complete();

你需要提交(commit)或回滚(rollback),就像这样:

$result = $this->db->trans_complete();

if($result === true){
    $this->db->trans_commit();
}else{
    $this->db->trans_rollback();
}

最终你想要的是:
$this->db->trans_off();

$this->db->query("insert this...");
$this->db->query("insert that...");

$result = $this->db->trans_complete();

if($result === true){
    $this->db->trans_commit();
}else{
    $this->db->trans_rollback();
}

如果我想要回滚事务,我该怎么做? - Pradip Talaviya
你对 trans_off() 的使用是错误的。一旦运行,其他任何 trans_ 方法都不会执行。嗯... 从技术上讲,它们会执行,但一旦它们看到 trans_off() 已被调用,它们立即返回 FALSE。 - DFriend

2

据我所知,对于CI版本3.0.1,你需要关注的唯一问题就是在何处放置$this->db->trans_start();$this->db->trans_complete();

因此,对于类似以下情况的情形:

$this->db->trans_start();
//any code goes here
$this->db->trans_complete();

如果出现问题,事务将被回滚,或者在调用$this->db->trans_complete();时提交。

因为如果您查看trans_start方法的内部,它包含trans_begin。而trans_complete方法包含对trans_status的检查,并相应地调用trans_committrans_rollback方法。

嵌套事务同样适用:

$this->db->trans_start();
//any code goes here
$this->db->trans_start();
//any code goes here
$this->db->trans_complete();
//any code goes here
$this->db->trans_complete();

默认情况下,Codeigniter在严格模式下运行所有事务,因此在最后的trans_complete时将全部提交,或者如果出现任何失败,则全部回滚。


2

为什么您想要ROLLBACK?是因为除了错误的trans_status之外的其他原因吗?如果是这样,请在调用trans_completetrans_commit之前先调用trans_rollback

听起来这对于您的情况是最佳选择(抱歉语法可能不正确):

trans_start
...
if ( some non-db problem )  trans_rollback
trans_complete

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接