【问题标题】:Codeigniter TransactionsCodeigniter 事务
【发布时间】:2013-02-19 21:57:00
【问题描述】:

我正在使用 Codeigniter 事务

$this->db->trans_start();
$this->db->query('AN SQL QUERY...');
$this->db->trans_complete();

这很好用,我遇到的问题是在trans_starttrans_complete 内部我正在调用其他函数,这些函数处理数据库,因此它们包含插入和更新以及一些删除......例如:

$this->db->trans_start();
 $this->utils->insert_function($data);
 $this->utils->update_function2($test);
$this->db->trans_complete();

现在,如果这些函数被执行并且发生一些错误,CodeIgniter 将不会进行回滚。

处理此类问题的最佳方法是什么?

我想到的唯一解决方案是从这些函数中返回一个错误,并在这些函数中添加(trans_stattrans_complete)如果它返回错误,请执行 $this->db->trans_rollback

例如:

    $this->db->trans_start();
     $result = $this->utils->insert_function($data);
     if($result === false){
       $this->db->trans_rollback();
     }
    $this->db->trans_complete();

有更好的方法吗?

更新 1:

根据要求提供我正在调用的外部函数的示例:

   // insert_function contains

    $rec = array(
        'numero' => $numero,
        'transaction_id' => $id,
        'debit' => $product_taxes['amount_without_taxes'],
        'date' => $data['date_transaction'],
    );
    $this->addExerciceAccountingRecords($rec);

  and addExerciceAccountingRecords contains

   function addExerciceAccountingRecords($records) {
    $this->db->insert('transactions_exercices', $records);
    }

【问题讨论】:

  • 您的 MySQL 表使用什么存储引擎?还有,你怎么知道回滚失败了?
  • @MarcAudet INNODB ,我知道是因为当在 trans_start 内的函数调用期间修改的表上没有应用回滚时
  • 您可以将代码发布到 utils->insert_function 和 utils->insert_function2 吗?我知道问题可能是什么......
  • @MarcAudet 我已经更新了我的问题。
  • 还有一个问题:utils 是否在libraries 文件夹中?

标签: php mysql codeigniter transactions codeigniter-3


【解决方案1】:

使用transactions 表示支持数据库安全插入数据。所以在 Codeigniter 中,我们在 Model 中而不是在 Controller. 中编写每个 数据库相关函数。。在您的第二个代码(不起作用)中,您已经在那里指出了模型。(utils)。如此简单,我相信这行不通。因为它不是模型和控制器并行的插入数据。交易应该在模型中编码(我将在我的答案中写在模型中)。


也加载这些东西

  1. 数据库库
  2. 模型类
  3. 网址助手
  4. 会话

假设

在您的代码中,您使用了 $data$test 作为数组。所以我假设有两个数组用于插入和更新数据。


您的数据集

$data = array(
   'title' => 'My title' ,
   'name' => 'My Name' ,
   'date' => 'My date'
);

$id = 007;
$test = array(
   'title' => $title,
   'name' => $name,
   'date' => $date
);

您的代码

$this->db->trans_start(); # Starting Transaction
$this->db->trans_strict(FALSE); # See Note 01. If you wish can remove as well 

$this->db->insert('table_name', $data); # Inserting data

# Updating data
$this->db->where('id', $id);
$this->db->update('table_name', $test); 

$this->db->trans_complete(); # Completing transaction

/*Optional*/

if ($this->db->trans_status() === FALSE) {
    # Something went wrong.
    $this->db->trans_rollback();
    return FALSE;
} 
else {
    # Everything is Perfect. 
    # Committing data to the database.
    $this->db->trans_commit();
    return TRUE;
}

备注

  1. 默认情况下,Codeigniter 以严格模式运行所有事务。什么时候 已启用严格模式,如果您正在运行多组事务,如果一组失败,所有组都将回滚。如果 严格模式禁用,每个组都治疗 独立意味着一个小组的失败不会影响 任何其他

【讨论】:

【解决方案2】:

我尝试的更多是一种技巧,但它对我有用。

$this->db->trans_begin();
  $rst1=  $this->utils->insert_function($data);
  $rst2 =  $this->utils->update_function2($test);
if($this->db->trans_status() === FALSE || !isset($rst1) || !isset($rst2)){
   $this->db->trans_rollback();
}else{
   $this->db->trans_commit();
}

【讨论】:

    【解决方案3】:

    我怀疑问题与 CodeIgniter 处理对象的方式有关。

    如果您访问“创建库”部分下的 CI 文档:
    http://ellislab.com/codeigniter/user-guide/general/creating_libraries.html
    并查看与以下相关的部分:

    $CI =& get_instance();
    $CI->load->helper('url');
    $CI->load->library('session');
    $CI->config->item('base_url');
    

    在您的主控制器中,您已经使用自动加载或显式加载类加载/实例化了数据库类。

    然后您继续打开事务,然后访问您的数据库 通过您的 utils 库执行函数。

    但是,一旦您在库中使用 $this-db,您实际上是在访问数据库实例的另一个副本,而不是与您的事务关联的副本。

    要访问同一个实例,需要使用 get_instance() 函数。

    我认为这应该可以解决您的问题。你原来的编码风格来分离功能 进入各种模块非常好。您只需要了解这些额外的细节。

    请尝试并确认回滚是否按预期进行。

    代码的核心由以下控制器组成:

    $this->db->trans_start();
    $this->User_profile_m->create_new_user_profile();
    $this->User_profile_m->create_new_user();
    $this->db->trans_complete(); 
    

    还有一个简单的模型user_profile_m来处理数据持久化:

    function create_new_user()
    {
        $data['user_name_usr'] = $this->input->post('user_name');
        $data['create_date_usr'] = NULL;
    
        $this->db->insert('user_usr', $data);  
    }
    
    function create_new_user_profile()
    {
        $data['user_name_pro'] = $this->input->post('user_name');
        $data['user_description_pro'] = $this->input->post('user_description');
        $data['create_date_pro'] = NULL;
    
        $this->db->insert('user_profile_pro', $data);  
    }
    

    本质上,演示尝试进行两次插入(两个表中的每一个)。 如果一个插入失败,则回滚另一个。

    我在 CodeIgniter 2.1.3 中构建了它,我可以通过 GitHub 提供应用程序文件或将它们压缩并发送给您。

    【讨论】:

    • 对不起,也许我举了一个不好的例子,即使插入函数在同一个模型中并且我通过 ($this->insertFunction...) 调用它也会出现问题
    • 嗨 Tarek,你试过 get_instance() 吗?我对此有点好奇;你没有做任何不寻常的事情。让我喝杯咖啡想一想,请今天晚些时候入住。
    • @Marc Audet:当更新操作返回 0(受影响的行)时,事务是否回滚?谢谢。
    • @secretim 好问题。您确实应该检查$this->db->trans_status() 而不是$this->db->affected_rows(),因为受影响的行结果可能会根据您放置语句的确切位置(在事务块内部或外部)而有所不同。
    【解决方案4】:


    注意:确保在运行手动事务时使用$this->db->trans_begin(),而不是$this->db->trans_start()

    $this -> db -> trans_begin(); 
    $this -> utils -> insert_function ( $data );
    $this -> utils -> update_function2 ( $test ); 
    $this -> db -> trans_complete ();
    

    认证以防使用MySql,以InnoDb格式使用

    【讨论】:

    • 为什么要投票?在两个版本(2 和 3)中,它是 start/completebegin/rollback/commit
    【解决方案5】:

    试试这个过程。它真的对我有用:)

    $this->db->trans_start();
       $this->utils->insert_function($data);
       $this->utils->update_function2($test);
    if($this->db->trans_status() === FALSE){
       $this->db->trans_rollback();
    }else{
       $this->db->trans_complete();
    }
    

    【讨论】:

    • trans_complete() 已经进行了状态检查和回滚/提交
    【解决方案6】:

    对于单个插入或更新记录,您可以使用affected_rows 函数

    $this->db->insert('table_name', xss_clean($data));
    
    
    //Check if there is a record affected
    if($this->db->affected_rows() > 0)
                  {
                      return true;
                  }
                  else
                  { 
                      // if not succeeded
                      // check your last query 
                      die($this->db->last_query());
                  }
    

    【讨论】:

      猜你喜欢
      • 2018-01-13
      • 2013-01-19
      • 1970-01-01
      • 2016-02-10
      • 2015-11-03
      • 2019-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多