Php mysql约束错误发生在it生产之后,我不确定是如何发生的

Php mysql约束错误发生在it生产之后,我不确定是如何发生的,php,mysql,sql,Php,Mysql,Sql,更新:发布了更多代码: 我有以下错误,在生产中发生过一次,我无法复制。(这件事发生在一位客户身上,他们不记得自己做了什么 我看到发生此错误的唯一方式是插入sales\u items失败,而没有导致代码停止处理。它们都在同一个循环中,因此应该具有有效的项目id 是否存在任何可能发生的竞争条件?(我在插入初始销售信息后使用mysql_insert_id())。这也是作为一个事务来完成的,因此它要么全部工作,要么全部失败 我不是在寻找一个确切的答案,而是一个如何/在哪里寻找的想法 来自New Reli

更新:发布了更多代码:

我有以下错误,在生产中发生过一次,我无法复制。(这件事发生在一位客户身上,他们不记得自己做了什么

我看到发生此错误的唯一方式是插入
sales\u items
失败,而没有导致代码停止处理。它们都在同一个循环中,因此应该具有有效的项目id

是否存在任何可能发生的竞争条件?(我在插入初始销售信息后使用mysql_insert_id())。这也是作为一个事务来完成的,因此它要么全部工作,要么全部失败

我不是在寻找一个确切的答案,而是一个如何/在哪里寻找的想法

来自New Relic的错误日志:

MysqlError:无法添加或更新子行:外键约束 失败(
phppoint\u CLIENTNAME
phppos\u sales\u items\u taxes
,约束
phppos\u sales\u items\u taxes\u ibfk\u 1
外键(
sale\u id
)参考
phppos\u销售项目
sale\u id

堆栈跟踪:

…t/public_html/PHP-Point-Of-Sale/system/database/drivers/mysql/
mysql_driver.php (179)
… at /home/phppoint/public_html/PHP-Point-Of-Sale/system/database/
DB_driver.php (453)
… at /home/phppoint/public_html/PHP-Point-Of-Sale/system/database/
DB_driver.php (299)
…/home/phppoint/public_html/PHP-Point-Of-Sale/system/database/
DB_active_rec.php (1196)
…ed at /home/phppoint/public_html/PHP-Point-Of-Sale/application/models/
sale.php (590)
…/home/phppoint/public_html/PHP-Point-Of-Sale/application/controllers/
sales.php (717)
in Sales::complete called at ? (?)
…ed at /home/phppoint/public_html/PHP-Point-Of-Sale/system/core/
CodeIgniter.php (359)
… require_once called at /home/phppoint/public_html/PHP-Point-Of-Sale/
index.php (211)
--
-- Table structure for table `phppos_sales_items`
--
application/models/sale.php中的最少代码示例

//Run these queries as a transaction, we want to make sure we do all or nothing
$this->db->trans_start();


//REMOVED CODE FOR UPDATING STORE ACCOUNT BALANCE

if ($sale_id)
{
    //Delete previoulsy sale so we can overwrite data
    $this->delete($sale_id, true);

    $this->db->where('sale_id', $sale_id);
    $this->db->update('sales', $sales_data);
}
else
{
    $this->db->insert('sales',$sales_data);
    $sale_id = $this->db->insert_id();
}


foreach($payments as $payment_id=>$payment)
{
    if ( substr( $payment['payment_type'], 0, strlen( lang('sales_giftcard') ) ) == lang('sales_giftcard') )
    {
        /* We have a gift card and we have to deduct the used value from the total value of the card. */
        $splitpayment = explode( ':', $payment['payment_type'] );
        $cur_giftcard_value = $this->Giftcard->get_giftcard_value( $splitpayment[1] );

        $this->Giftcard->update_giftcard_value( $splitpayment[1], $cur_giftcard_value - $payment['payment_amount'] );
        $total_giftcard_payments+=$payment['payment_amount'];
    }

    $sales_payments_data = array
    (
        'sale_id'=>$sale_id,
        'payment_type'=>$payment['payment_type'],
        'payment_amount'=>$payment['payment_amount'],
        'payment_date' => $payment['payment_date'],
        'truncated_card' => $payment['truncated_card'],
        'card_issuer' => $payment['card_issuer'],
    );
    $this->db->insert('sales_payments',$sales_payments_data);
}


foreach($items as $line=>$item)
{
    if (isset($item['item_id']))
    {
        $cur_item_info = $this->Item->get_info($item['item_id']);
        $cur_item_location_info = $this->Item_location->get_info($item['item_id']);

        if ($item['item_id'] != $store_account_item_id)
        {
            $cost_price = ($cur_item_location_info && $cur_item_location_info->cost_price) ? $cur_item_location_info->cost_price : $cur_item_info->cost_price;
        }
        else // Set cost price = price so we have no profit
        {
            $cost_price = $item['price'];
        }

        //Add to the cost price if we are using a giftcard as we have already recorded profit for sale of giftcard
        if (!$has_added_giftcard_value_to_cost_price)
        {
            $cost_price+= $total_giftcard_payments;
            $has_added_giftcard_value_to_cost_price = true;
        }

        $reorder_level = ($cur_item_location_info && $cur_item_location_info->reorder_level) ? $cur_item_location_info->reorder_level : $cur_item_info->reorder_level;

        if ($cur_item_info->tax_included)
        {
            $item['price'] = get_price_for_item_excluding_taxes($item['item_id'], $item['price']);
        }

        $sales_items_data = array
        (
            'sale_id'=>$sale_id, //from mysql_insert_id()
            'item_id'=>$item['item_id'],
            'line'=>$item['line'], //Server side validated
            'description'=>$item['description'], //Server side validated
            'serialnumber'=>$item['serialnumber'], //Server side validated
            'quantity_purchased'=>$item['quantity'], //Server side validated
            'discount_percent'=>$item['discount'],//Server side validated
            'item_cost_price' =>  $cost_price, //Server side validated
            'item_unit_price'=>$item['price'] //Server side validated
        );


        $this->db->insert('sales_items',$sales_items_data);

        //REMOVED CODE TO UPDATE GIFTCARD BALANCE

        //REMOVED CODE FOR EMAIL ALERTS

        //REMOVED CODE FOR INVENTORY LOGGING
    }
    else
    {
        $cur_item_kit_info = $this->Item_kit->get_info($item['item_kit_id']);
        $cur_item_kit_location_info = $this->Item_kit_location->get_info($item['item_kit_id']);

        //REMOVE CODE FOR GIFTCARD BALANCE

        $sales_item_kits_data = array
        (
            'sale_id'=>$sale_id,
            'item_kit_id'=>$item['item_kit_id'],
            'line'=>$item['line'],
            'description'=>$item['description'],
            'quantity_purchased'=>$item['quantity'],
            'discount_percent'=>$item['discount'],
            'item_kit_cost_price' => $cost_price === NULL ? 0.00 : $cost_price,
            'item_kit_unit_price'=>$item['price']
        );

        $this->db->insert('sales_item_kits',$sales_item_kits_data);

        foreach($this->Item_kit_items->get_info($item['item_kit_id']) as $item_kit_item)
        {
            $cur_item_info = $this->Item->get_info($item_kit_item->item_id);
            $cur_item_location_info = $this->Item_location->get_info($item_kit_item->item_id);

            //REMOVED CODE FOR EMAIL ALERTS

            //REMOVED CODE FOR INVENTORY LOGGING
        }
    }

    $customer = $this->Customer->get_info($customer_id);
    if ($customer_id == -1 or $customer->taxable)
    {
        if (isset($item['item_id']))
        {
            foreach($this->Item_taxes_finder->get_info($item['item_id']) as $row)
            {
                $this->db->insert('sales_items_taxes', array(
                    'sale_id'   =>$sale_id,
                    'item_id'   =>$item['item_id'],
                    'line'      =>$item['line'],
                    'name'      =>$row['name'],
                    'percent'   =>$row['percent'],
                    'cumulative'=>$row['cumulative']
                ));
            }
        }
        else
        {
            foreach($this->Item_kit_taxes_finder->get_info($item['item_kit_id']) as $row)
            {
                $this->db->insert('sales_item_kits_taxes', array(
                    'sale_id'       =>$sale_id,
                    'item_kit_id'   =>$item['item_kit_id'],
                    'line'          =>$item['line'],
                    'name'          =>$row['name'],
                    'percent'       =>$row['percent'],
                    'cumulative'    =>$row['cumulative']
                ));
            }                   
        }
    }
}
$this->db->trans_complete();

if ($this->db->trans_status() === FALSE)
{
    return -1;
}
数据库表:

DROP TABLE IF EXISTS `phppos_sales_items`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `phppos_sales_items` (
  `sale_id` int(10) NOT NULL DEFAULT '0',
  `item_id` int(10) NOT NULL DEFAULT '0',
  `description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `serialnumber` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `line` int(3) NOT NULL DEFAULT '0',
  `quantity_purchased` decimal(23,10) NOT NULL DEFAULT '0.0000000000',
  `item_cost_price` decimal(23,10) NOT NULL,
  `item_unit_price` decimal(23,10) NOT NULL,
  `discount_percent` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`sale_id`,`item_id`,`line`),
  KEY `item_id` (`item_id`),
  CONSTRAINT `phppos_sales_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `phppos_items` (`item_id`),
  CONSTRAINT `phppos_sales_items_ibfk_2` FOREIGN KEY (`sale_id`) REFERENCES `phppos_sales` (`sale_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;



--
-- Table structure for table `phppos_sales_items_taxes`
--

DROP TABLE IF EXISTS `phppos_sales_items_taxes`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `phppos_sales_items_taxes` (
  `sale_id` int(10) NOT NULL,
  `item_id` int(10) NOT NULL,
  `line` int(3) NOT NULL DEFAULT '0',
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `percent` decimal(15,3) NOT NULL,
  `cumulative` int(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`sale_id`,`item_id`,`line`,`name`,`percent`),
  KEY `item_id` (`item_id`),
  CONSTRAINT `phppos_sales_items_taxes_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `phppos_sales_items` (`sale_id`),
  CONSTRAINT `phppos_sales_items_taxes_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `phppos_items` (`item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

那你为什么要关闭你的
if(isset($item['item_id']){
,仅仅是为了直接重新开始一个相同的新项目?你是否剪掉了中间的一些代码?这可能是重要的代码。@nl-x更新了更多的代码