php - 内存耗尽cakephp数据库查询

标签 php mysql cakephp memory cakephp-2.x

我是 CakePHP 2.4 的新手,我希望有人能帮助我解决我遇到的问题。

我的项目中存在内存耗尽的问题 - 我已经对其进行了调试并使所有内容都可以使用 2 GB 内存 - 但我的网络托管公司只允许 1 GB。

所以我想知道是什么导致 MySQL 使用了这么多 RAM - 当我向订单添加优惠券时会发生这种情况 - 优惠券包含我商店中的所有产品。

我在导致问题的行和一长串数组(大约 1200 A4 页)之前放置了调试 - 我发现很多,我想这就是为什么 mysql.php 在 cake 中出现以下错误:

Fatal error: Allowed memory size of 188743680 bytes exhausted 
(tried to allocate 32 bytes) in lib/Cake/Model/Datasource/Database/Mysql.php on line 277

有没有办法解决这个问题——要么减少调用量,要么增加内存。

已编辑:我认为问题不是 Coupon Controller /模型,而是订单模型导致它获取所有产品 - 已提供以下代码:

希望有人会看一下它并给我一些提示,告诉我如何让它工作。 我试过调试内存使用情况,它只使用了大约 3 MB - 但是当添加优惠券时,它只会淹没内存并永远运行。

订单模型

<?php
App::uses('AppModel', 'Model');

class Order extends AppModel
{
    public $displayField = 'id';

    private $shipping_price = 39;
    private $free_shipping_threshold = 500;
    private $tax_rate = 0.20;

    public $validate = array(
        'state' => array(
            'rule'    => array('inList', array('unplaced', 'received', 'packed', 'resolved')),
            'allowEmpty' => false,
            'message' => 'Du skal vælge et stadie.'
         ),
        'shipping_price' => array(
            'decimal' => array(
                'rule' => 'decimal',
                'allowEmpty' => false,
                'message' => 'Du skal angive en pris.',
            ),
            'notNegative' => array(
                'rule'    => array('comparison', '>=', 0),
                'message' => 'En pris kan ikke være negativ.'
            )
        ),
    );

    public $hasMany = array(
        'OrderItem'
    );

    public $belongsTo = array(
        'Customer',
        'Coupon'
    );

    private function purgeInactives($order_id)
    {
        // Find the order
        $order = $this->find('first', array('conditions' => array('Order.id' => $order_id), 'recursive' => 2));

        // Run through all order items in the order
        foreach ($order['OrderItem'] as $key => $order_item) {

        // Check if the order was a yarn batch
            if ($order_item['yarn_batch_id'] != 0) {
            // Check if the item is active
                if (!$order_item['YarnBatch']['is_active']) {
                    $this->OrderItem->delete($order_item['id']);
                    SessionComponent::setFlash(' Der blev fjernet en varer fra din indkøbskurv da det er ikke længere er aktivt. '.SessionComponent::read('Message.warning.message'), null, array(), 'warning');
                } // Check if there are any of this item left in stock
                else if ($order_item['YarnBatch']['stock_quantity'] < 1) {
                    $this->OrderItem->delete($order_item['id']);
                    SessionComponent::setFlash(' En af varene i din indkøbskurv er ikke længere på lager. '.SessionComponent::read('Message.warning.message'), null, array(), 'warning');
                }
            } // Check if the order was a needle variant
            else if ($order_item['needle_variant_id'] != 0) {
            // Check if the item is active
                if (!$order_item['NeedleVariant']['is_active']) {
                    $this->OrderItem->delete($order_item['id']);
                    SessionComponent::setFlash(' Der blev fjernet en varer fra din indkøbskurv da det er ikke længere er aktivt. '.SessionComponent::read('Message.warning.message'), null, array(), 'warning');
                } // Check if there are any of this item left in stock
                else if ($order_item['NeedleVariant']['stock_quantity'] < 1) {
                    $this->OrderItem->delete($order_item['id']);
                    SessionComponent::setFlash(' En af varene i din indkøbskurv er ikke længere på lager. '.SessionComponent::read('Message.warning.message'), null, array(), 'warning');
                }
            } // Check if the order was a recipe
            else if ($order_item['recipe_id'] != 0) {
            // Check if the item is active
                if (!$order_item['Recipe']['is_active']) {
                    $this->OrderItem->delete($order_item['id']);
                    SessionComponent::setFlash(' Der blev fjernet en varer fra din indkøbskurv da det er ikke længere er aktivt. '.SessionComponent::read('Message.warning.message'), null, array(), 'warning');
                }
            } else if ($order_item['color_sample_id'] != 0) {
            // Check if the item is active
                if (!$order_item['ColorSample']['is_active']) {
                    $this->OrderItem->delete($order_item['id']);
                    SessionComponent::setFlash(' Der blev fjernet en varer fra din indkøbskurv da det er ikke længere er aktivt. '.SessionComponent::read('Message.warning.message'), null, array(), 'warning');
                }
            } else {
                $this->OrderItem->delete($order_item['id']);
            }
        }
        // If the order have a coupon and it is no long active
        // if ($order['Coupon']['id'] !=0 && !$order['Coupon']['is_active']) {
        //     SessionComponent::setFlash(' Kuponen i din indkøbskurv blev fjernet fordi den ikke længere er gyldig. '.SessionComponent::read('Message.warning.message'), null, array(), 'warning');
        //     $this->Order->set($order);
        //     $this->Order->saveField('coupon_id', null);
        // }

    }

    private function resetOrderItemsPrices($order_id)
    {
        $order_items = $this->OrderItem->find('all', array('conditions' => array('OrderItem.order_id' => $order_id)));

        foreach ($order_items as $key => $order_item) {
            $this->OrderItem->set($order_item);
            $this->OrderItem->resetPrice();
        }
    }

    public function refresh()
    {
        // Remove edited or removed items
        $this->purgeInactives($this->id);
        $this->resetOrderItemsPrices($this->id);

        $order = $this->find('first', array('conditions' => array('Order.id' => $this->id), 'recursive' => 2));


        // Items order by prices, highest first
        $order_items = Set::sort($order['OrderItem'], '{n}.price', 'desc');
        $order_price = 0;
        $order_saving = 0;
        $total_amount_of_items = 0;

        $is_only_color_samples = true;

        // Run through all items
        foreach ($order_items as $key => $order_item) {
            $new_total_item_price = $order_item['price'];
            if ($order['Coupon']['id'] != 0) {
                if ($order_item['yarn_batch_id'] != 0) {
                    // There exist an item that is not a color sample
                    $is_only_color_samples = false;
                    foreach ($order['Coupon']['YarnBatch'] as $key => $yarn_batch_on_coupon) {

                        if ($yarn_batch_on_coupon['id'] == $order_item['yarn_batch_id']) {
                            // Calcualte savings
                            $calculated_savings = $this->calculateSaving(
                                $yarn_batch_on_coupon['price'],
                                $order_item['amount'],
                                $order['Coupon']['percentage_discount'],
                                $order['Coupon']['actual_discount'],
                                $order['Coupon']['item_amount']
                            );

                            // Was this a better soloution
                            if ($order_item['saving'] < $order_item['price'] - $calculated_savings['new_total_item_price']) {
                                $new_total_item_price = $calculated_savings['new_total_item_price'];
                                $best_coupon['amount_left'] = $calculated_savings['coupon_item_amount_left'];
                                $best_coupon['id'] = $order['Coupon']['id'];
                            }
                        } else {
                            continue;
                        }

                    }
                } else if ($order_item['needle_variant_id'] != 0) {
                    // There exist an item that is not a color sample
                    $is_only_color_samples = false;

                    if (!$order_item['NeedleVariant']['is_active']) {
                        foreach ($order['Coupon']['YarnBatch'] as $key => $yarn_batch_on_coupon) {
                            if ($needle_variant_on_coupon['id'] == $order_item['needle_variant_id']) {
                                // Calcualte savings
                                $calculated_savings = $this->calculateSaving(
                                    $needle_variant_on_coupon['price'],
                                    $order_item['amount'],
                                    $order['Coupon']['percentage_discount'],
                                    $order['Coupon']['actual_discount'],
                                    $order['Coupon']['item_amount']
                                );

                                // Was this a better soloution
                                if ($order_item['saving'] < $order_item['price'] - $calculated_savings['new_total_item_price']) {
                                    $new_total_item_price = $calculated_savings['new_total_item_price'];
                                    $best_coupon['amount_left'] = $calculated_savings['coupon_item_amount_left'];
                                    $best_coupon['id'] = $order['Coupon']['id'];
                                }
                            } else {
                                continue;
                            }
                        }
                    }
                } else if ($order_item['recipe_id'] != 0) {
                    // There exist an item that is not a color sample
                    $is_only_color_samples = false;
                }

                $order_item['saving'] = $order_item['price'] - $new_total_item_price;

            }

                // Calucalte the prices of item
                $order_saving += $order_item['saving'];
                $order_price += $order_item['price'] - $order_item['saving'];

                // Store prices on item
                $this->OrderItem->set($order_item);
                $this->OrderItem->saveField('saving', $order_item['saving']);
                $this->OrderItem->saveField('price', $order_item['price'] - $order_item['saving']);

            // Count up the counter
            $total_amount_of_items += $order_item['amount'];
        }
        $shipping_price = 0;

        // Calculate shipping prince and remainder (if it is only color samples keep it at 0)
        if ($order_price < $this->free_shipping_threshold) {
            $shipping_price = $this->shipping_price;
        }

        $free_shipping_remainder = $this->free_shipping_threshold - $order_price;



        $order_price = $order_price + $shipping_price;

        // Calculate taxing
        $tax = $order_price * $this->tax_rate;
        $sub_total = $order_price - $tax;

        // Store order data
        $this->saveField('shipping_price', $shipping_price);
        $this->saveField('free_shipping_remainder', $free_shipping_remainder);
        $this->saveField('amount', $total_amount_of_items);
        $this->saveField('saving', $order_saving);
        $this->saveField('price', $order_price);
        $this->saveField('tax', $tax);
        $this->saveField('sub_total', $sub_total);
        $this->saveField('modified', date('Y-m-d H:i:s'));

    }

    private function calculateSaving($item_price, $item_amount, $coupon_saving_percent, $coupon_saving_actual, $coupon_item_amount)
    {
        $new_item_price = 0;
        $new_total_item_price = 0;
        $coupon_item_amount_left = 0;

        // Check if the percentage discount is null, then use actual discount otherwise use percentage
        if ($coupon_saving_percent == null) {
            $new_item_price = $item_price - $coupon_saving_actual;
            $new_item_price = $new_item_price < 0 ? 0 : $new_item_price;
        } else {
            $new_item_price = $item_price - ($item_price * $coupon_saving_percent/100 );
        }

        // Check if there is enough to get savings on all of this particular item
        if ($item_amount <= $coupon_item_amount) {
            $new_total_item_price = $new_item_price * $item_amount;
            $coupon_item_amount_left = $coupon_item_amount - $item_amount;
        } else {
            $new_total_item_price = $new_item_price * $coupon_item_amount + $item_price * ($item_amount - $coupon_item_amount);
            $coupon_item_amount_left = $coupon_item_amount;
        }

        return array('new_total_item_price' => $new_total_item_price, 'coupon_item_amount_left' => $coupon_item_amount_left);
    }

    public function updateStockQuantityAfterPurchase()
    {
        // Find the order
        $order = $this->find('first', array('conditions' => array('Order.id' => $this->id), 'recursive' => 2));

        // Run through all order items in the order
        foreach ($order['OrderItem'] as $key => $order_item) {
        // Check if the order was a yarn batch
            if ($order_item['yarn_batch_id'] != 0) {
            // Find the item
                $yarn_batch = $this->OrderItem->YarnBatch->find('first', array('conditions' => array('YarnBatch.id' => $order_item['yarn_batch_id'])));

                // Calculate new stock amount
                $new_stock_quantity = $yarn_batch['YarnBatch']['stock_quantity'] - $order_item['amount'];

                $this->OrderItem->YarnBatch->id = $yarn_batch['YarnBatch']['id'];
                $this->OrderItem->YarnBatch->saveField('stock_quantity', $new_stock_quantity);
            } // Check if the order was a needle variant
            else if ($order_item['needle_variant_id'] != 0) {
            // Find the item
                $needle_variant = $this->OrderItem->NeedleVariant->find('first', array('conditions' => array('NeedleVariant.id' => $order_item['needle_variant_id'])));

                // Calculate new stock amount
                $new_stock_quantity = $needle_variant['NeedleVariant']['stock_quantity'] - $order_item['amount'];

                $this->OrderItem->NeedleVariant->id = $needle_variant['NeedleVariant']['id'];
                $this->OrderItem->NeedleVariant->saveField('stock_quantity', $new_stock_quantity);
            }
        }

        // If the order have a coupon and it is no long active
        if ($order['Coupon']['id'] != 0 && !$order['Coupon']['is_active']) {
            SessionComponent::setFlash(' Kuponnen i din indkøbskurv blev fjernet fordi den ikke længere er gyldig. '.SessionComponent::read('Message.warning.message'), null, array(), 'warning');
            $this->Order->set($order);
            $this->Order->saveField('coupon_id', null);
        }

    }
}

最佳答案

188743680 字节是 180meg,所以你没有耗尽你的 1GB 内存。但是,PHP 可能已配置为使用最大 180Meg。

您让它在具有 2Gb 内存的机器上运行的事实是无关紧要的,php.ini memory_limit 在另一台机器上设置的是什么。

如果您有权访问 php.ini 文件,则可以通过将 memory_limit = 180M 修改为更大的数字来更改此限制。

但我想说您的问题更可能与您处理结果集的方式有关,因此查看重构查询和处理查询结果的 PHP 可能是个好主意。

关于php - 内存耗尽cakephp数据库查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34673272/

相关文章:

cakephp - 在 Cakephp 中保存与同一模型相关的多个记录

php - Codeigniter 替换上传的图片

php - 我怎样才能让我的 php 只从 mysql 返回某个 id

cakephp - 无法在 cakephp 2.x 中获取带有链接的图像?

PHP SQLSTATE[HY000] [1045] 用户 Laravel 访问被拒绝

mysql - PHP - 通知 : Undefined index:

mysql - 带条件的 Cakephp 模型

php - php 包的文档?

php - PHP 与 firebase 的连接如何工作?

php - 搜索多行mysql