php - CodeIgniter 事务 - trans_status 和 trans_complete 返回 true 但没有提交任何内容

标签 php mysql codeigniter

问题:

我在我的模型中编写了一个函数来将订单插入到我的数据库中。我正在使用事务来确保所有内容都提交,否则它将被回滚。

我的问题是 CodeIgniter 没有显示任何数据库错误,但是它正在回滚事务,然后返回 TRUEtrans_status .但是,这仅在订单有折扣时才会发生。如果订单没有折扣,则一切正常并正常工作。

我目前使用的是 CodeIgniter 3.19、PHP (7.2)、mySQL (5.7) 和 Apache 2.4。 (在 Ubuntu 18.04 上工作)

函数逻辑是这样工作的:

  • 将订单数组插入 tbl_orders
  • 保存 order_id ,并遍历每个订单产品(附加 order_id )并将产品插入 tbl_order_products ,
  • 保存 order_product_id并将其附加到一系列用户出勤选项并将其插入 tbl_order_attendance
  • 获取支付交易数组(附加 order_id )并将其插入到 tbl_transactions
  • 如果订单有折扣 ,它减少了 discount_redeem_count (可兑换折扣代码的数量)乘以 1。

  • 实际功能

    [功能]:
    public function add_order(Order $order, array $order_products, Transaction $transaction = NULL){
      $this->db->trans_start();
    
      $order->create_order_code();
      $order_array = $order->create_order_array();
    
      $this->db->insert('tbl_orders', $order_array);
      $order_id = $this->db->insert_id();
      $new_order = new Order($order_id);
    
      foreach($order_products as $key=>$value){
        $order_products[$key]->set_order($new_order);
        $order_product_array = $order_products[$key]->create_order_product_array();
    
        $this->db->insert('tbl_order_products', $order_product_array);
        $order_product_id = $this->db->insert_id();
    
        $product = $order_products[$key]->get_product();
    
        switch ($product->get_product_class()){
            case 'Iteration':
                $this->db->select('module_id, webcast_capacity, in_person_capacity');
                $this->db->from('tbl_modules');
                $this->db->where('iteration_id', $product->get_product_class_id());
                $results = $this->db->get()->result_array();
                break;
            case 'Module':
                $this->db->select('module_id, webcast_capacity, in_person_capacity');
                $this->db->from('tbl_modules');
                $this->db->where('module_id', $product->get_product_class_id());
                $results = $this->db->get->result_array();
                break;
          }
    
          if(!empty($results)){
            foreach($results as $result){
            $module_id = $result['module_id'];
    
            if($result['webcast_capacity'] !== NULL && $result['in_person_capacity'] !== NULL){
              $attendance_method = $order_products[$key]->get_attendance_method();
            }elseif($result['webcast_capacity'] !== NULL && $result['in_person_capacity'] === NULL){
              $attendance_method = 'webcast';
            }elseif($result['webcast_capacity'] === NULL && $result['in_person_capacity'] !== NULL){
              $attendance_method = 'in-person';
            }
    
            $order_product_attendance_array = array(
              'order_product_id' => $order_product_id,
              'user_id' => $order_products[$key]->get_customer(true),
              'module_id' => $module_id,
              'attendance_method' => $attendance_method,
            );
    
            $order_product_attendance[] = $order_product_attendance_array;
          }
          $this->db->insert_batch('tbl_order_product_attendance', $order_product_attendance);
        }
    
        if(!empty($order_products[$key]->get_discount())){
          $discount = $order_products[$key]->get_discount();
        }
      }
    
      if(!empty($transaction)){
        $transaction->set_order($new_order);
        $transaction_array = $transaction->create_transaction_array();
        $this->db->insert('tbl_transactions', $transaction_array);
        $transaction_id = $this->db->insert_id();
      }
    
      if(!empty($discount)){
        $this->db->set('discount_redeem_count', 'discount_redeem_count-1', false);
        $this->db->where('discount_id', $discount->get_discount_id());
        $this->db->update('tbl_discounts');
      }
    
      if($this->db->trans_status() !== false){
        $result['outcome'] = true;
        $result['insert_id'] = $order_id;
        return $result;
      }else{
        $result['outcome'] = false;
        return $result;
      }
    }
    

    当此功能完成时 有折扣 , 两者 trans_completetrans_status返回 TRUE .但是,事务永远不会提交。

    我试过的:
  • 我已经转储了 $this->db->error() 的内容在每次查询之后,并且在任何查询中都没有错误。
  • 我用过 this->db->last_query()打印出每个查询,然后在线检查语法以查看是否有任何问题,没有。
  • 我还尝试更改为使用 CodeIgniters 手动事务,例如:

  • [例子]
    $this->db->trans_begin();
     // all the queries
    if($this->db->trans_status() !== false){
        $this->db->trans_commit();
        $result['outcome'] = true;
        $result['insert_id'] = $order_id;
        return $result;
    }else{
        $this->db->trans_rollback();
        $result['outcome'] = false;
        return $result;
    }
    
  • 我试过 echo ing 和 var_dump ing 所有的返回 insert_ids他们都工作了,我也输出了affected_rows()UPDATE查询并显示 1 行已更新。但是,仍然没有提交任何内容:

  • [转储值]
    int(10) // order_id
    int(10) // order_product_id
    array(3) { 
        ["module_id"]=> string(1) "1" 
        ["webcast_capacity"]=> string(3) "250" 
        ["in_person_capacity"]=> string(3) "250" } // $results array (modules)
    
    array(1) { 
        [0]=> array(4) { 
            ["order_product_id"]=> int(10 
            ["user_id"]=> string(1) "5" 
            ["module_id"]=> string(1) "1" 
            ["attendance_method"]=> string(7) "webcast" } } // order_product_attendance array
    
    int(9) // transaction_id
    int(1) // affected rows
    string(99) "UPDATE `tbl_discounts` 
                SET discount_redeem_count = discount_redeem_count- 1 
                WHERE `discount_id` = 1" // UPDATE query
    

    - 我也试过更换最后一个 UPDATE使用完全不同的查询尝试更新具有不同值的不同表。该查询也不起作用,这让我认为我在交易中遇到了某种内存限制。但是,监控时mysqld过程,它们似乎都没有尖峰或有困难。
  • 我试过提交一个没有折扣的订单,整个过程都有效!这让我相信我的问题出在我的 UPDATE 查询上。 [更新后:] 但似乎更新查询也有效。

  • 尝试过的建议:
  • 我们试过设置 log_threshold到 4,并查看 CodeIgniter 日志文件,其中没有显示回滚的历史记录。
  • 我们检查了 mySQL 查询日志:

  • 【查询日志】
    2018-12-03T15:20:09.452725Z         3 Query     UPDATE `tbl_discounts` SET discount_redeem_count = discount_redeem_count-1 WHERE `discount_id` = '1'
    2018-12-03T15:20:09.453673Z         3 Quit
    

    它表明 QUIT命令在 UPDATE 之后直接发送询问。这将启动回滚,但是 trans_status正在返回 TRUE .

    我也换了 my.cnf用于 mySQL 的文件 innodb_buffer_pool_size=256Minnodb_log_file_size=64M .结果没有任何变化。
  • 按照@ebcode 的建议,我更改了 UPDATE查询使用 simple_query()而不是使用 CodeIgniter 的查询生成器类中的默认方法:

  • 【简单查询】
    if(!empty($discount)){
        $this->db->simple_query('UPDATE `tbl_discounts` SET '.
        'discount_redeem_count = discount_redeem_count-1 WHERE '.
        '`discount_id` = \''.$discount['discount_id'].'\'');
    }
    

    然而,这种产生并没有对结果产生任何不同的影响。

    如果您有我还没有尝试过的想法,或者需要我提供更多信息,请发表评论,我会及时回复。

    题:

    为什么trans_status返回 TRUE如果我的交易都没有被提交?

    为了尝试为现在才发现此问题的用户提供一些清晰度,帖子的最新更新将以斜体显​​示 *

    最佳答案

    我发现了我的问题。我想对所有试图提供帮助的人说声谢谢,但这是我的错。

    在调用此函数的 Controller 方法的早些​​时候,我调用了另一个启动事务的函数。该交易从未关闭,因此继续进行此新交易。

    因为事务没有提交并且没有错误,所以我找不到任何错误或回滚的任何历史记录。但是,一旦我关闭了之前的交易,一切都正常了。

    在 mySQL 查询日志、mySQL 错误日志或 CodeIgniter 错误日志中没有任何问题的证据。我只能通过慢慢阅读整个mySQL查询日志才能找到这个问题。

    对于遇到此问题的任何人:检查您的其他交易并确保它们都已关闭。

    关于php - CodeIgniter 事务 - trans_status 和 trans_complete 返回 true 但没有提交任何内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53564839/

    相关文章:

    php - 如何将mysql数据的一列或多列存储在数组中

    mysql - 如何在sequelize、node js中使用like in where条件

    java - 如何修改比较和操作mysql和Java中的日期时间值?

    php - 如何通过存储过程将文件插入MySQL数据库?

    php - Crypt() 盐生成和密码加密,执行得好吗?

    php - Paypal 成功网址无效 : Codeigniter

    php - 如何使用注入(inject)的 SerializerInterface 配置 Normalizer

    php - session /数组问题,购物车

    php - 计算组合指数

    php - MySql如何在1个查询中选择具有2个不同where条件的总和列