CodeIgniter Transactions - trans_status和trans_complete返回 true,但未提交任何内容

2022-08-30 23:44:57

问题:

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

我的问题是CodeIgniter没有显示任何数据库错误,但是它正在回滚事务,但随后返回TRUE trans_status。但是,仅当订单有折扣时,才会发生这种情况。如果订单没有折扣,则一切都会提交并正常工作。

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

函数逻辑的工作原理如下:

  • 将订单数组插入到tbl_orders
  • 保存 ,并遍历每个订单产品(附加),并将产品插入 ,order_idorder_idtbl_order_products
  • 将其保存并附加到一系列用户出勤选项中,并将其插入到order_product_idtbl_order_attendance
  • 获取付款交易记录数组(附加 ) 并将其插入到order_idtbl_transactions
  • 如果订单有折扣,则会将(可兑换折扣代码的数量)减少 1。discount_redeem_count

实际功能

[功能]:

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_statusTRUE

我尝试过:

  • 我已经在每个查询之后转储了的内容,并且任何查询中都没有错误。$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;
}
  • 我已经尝试了和所有返回,它们都有效,我还输出了查询的,它显示1行已更新。但是,仍然没有提交任何内容:echovar_dumpinsert_idsaffected_rows()UPDATE

[转储值]

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查询有关。[更新后:]但更新查询似乎也在工作。

已尝试的建议:

  • 我们尝试设置为4,并查看了CodeIgniter日志文件,其中没有显示回滚的历史记录。log_threshold

  • 我们已经检查了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

它显示命令是在查询后直接发送的。这将启动回滚,但是 返回 。QUITUPDATEtrans_statusTRUE

我还将 mySQL 的文件更改为 具有 和 .结果没有变化。my.cnfinnodb_buffer_pool_size=256Minnodb_log_file_size=64M

  • 根据@ebcode建议,我将查询更改为使用 CodeIgniter 的查询生成器类中的默认方法,而不是使用默认方法:UPDATEsimple_query()

[简单查询]

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,如果我的交易没有被提交?

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


答案 1

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

在调用此函数的 Controller 方法的前面,我调用了另一个启动事务的函数。该交易从未完成,因此继续进行这一新交易。

由于事务只是未提交并且没有错误,因此我无法找到任何错误或任何回滚历史记录。但是,一旦我关闭了以前的交易,一切都有效。

没有证据表明 mySQL 查询日志、mySQL 错误日志或 CodeIgniter 错误日志中存在任何问题。我只能通过慢慢阅读整个mySQL查询日志来发现这个问题。

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


答案 2

也许尝试将更新代码替换为对simple_query调用?

改变:

if(!empty($discount)){
    $this->db->set('discount_redeem_count', 'discount_redeem_count-1', false);
    $this->db->where('discount_id', $discount['discount_id']);
    $this->db->update('tbl_discounts');
}

自:

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

我稍微浏览了一下CodeIgniter源代码,看起来默认查询函数做了很多可能搞砸的事情。simple_query函数有这样的文档:

/**
 * Simple Query
 * This is a simplified version of the query() function. Internally
 * we only use it when running transaction commands since they do
 * not require all the features of the main query() function.
 *
 * @param   string  the sql query
 * @return  mixed
 */

推荐