mysql约束错误一旦生成就发生了,我不确定如何

时间:2014-05-14 21:27:21

标签: php mysql sql

更新:发布更多代码:

我在生产中发生了以下错误,我无法重现。 (它发生在一个客户身上,他们不记得他们做了什么导致它。

我发现此错误发生的唯一方法是插入sales_items失败而不导致代码停止处理。它们都在同一个循环中,因此它应该具有有效的项ID。

是否有可能发生的竞争条件? (我在插入初始销售信息后使用mysql_insert_id())。这也是作为一个交易完成的,所以它全部有效或全部失败。

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

New Relic的错误记录:

  

MysqlError:无法添加或更新子行:外键约束   失败(phppoint_CLIENTNAMEphppos_sales_items_taxes,CONSTRAINT   phppos_sales_items_taxes_ibfk_1 FOREIGN KEY(sale_id)参考   phppos_sales_itemssale_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 */;

0 个答案:

没有答案