Проблема с циклическим выполнением запросов

Общие вопросы по использованию фреймворка. Если не знаете как что-то сделать и это про Yii, вам сюда.
Ответить
pioneer
Сообщения: 136
Зарегистрирован: 2013.03.10, 23:27

Проблема с циклическим выполнением запросов

Сообщение pioneer »

Доброго времени суток, уважаемые форумчане!
На сайте имеется функционал синхронизации xml-выгрузок товаров (система 1С выгружает данные в xml, сайт парсит это дело и по определенному атрибуту либо добавляет товары, либо обновляет существующие). Так вот, сам функционал синхронизации на мой взгляд написан добротно, однако очень часто сам процесс синхронизации попросту не происходит - об этом свидетельствуют счетчики добавленных/измененных товаров. Например, мне за один раз нужно синхронизировать несколько выгрузок: в первой из них суммарное число товаров (строк) в файле - 20 - при этом счетчики сообщают (например) : добавлено 10 новых товаров, обновлено 10 существующих товаров, при синхронизации второго файла (выгрузки, в которой 30 товаров) счетчики пишут точно такие же показатели - я конечно же сразу догадался, что всему виной кеширование запросов - и тут я и пытался перед каждой синхронизацией полностью очищать кеш (на сайте юзается CMS Yupe, но это не столь важно), и в самой функции вначале делать вот так:

Код: Выделить всё

$connection = Yii::app()->db;
// очистка из кэша схемы таблицы Товаров
$connection->schema->getTable('catalog_good', true);
- проблема не исчезла.
В config/db.php:

Код: Выделить всё

'schemaCachingDuration' => 86400,
Подскажите, пожалуйста, в чем может быть проблема и что следует предпринять?
Мои пока неопробованные варианты и догадки:
1) Выставить 'schemaCachingDuration' => 0
2) Таблицу товаров (ибо только по ней происходят синхронизации) добавить в исключения: 'schemaCachingExclude' => ['catalog_good']
3) Попробовать очищать кеш $connection->schema->getTable('catalog_good', true); не в начале функции, а перед и после каждого запроса (ведь в функции присутствует цикл) - возможно, в этом дело?
4) Возможно всему виной какое-либо кеширование, включенное в самих настройках сервера (в php.ini) или мускуля? - Такое возможно?

Большое спасибо за помощь заранее!
question.guy
Сообщения: 13
Зарегистрирован: 2016.03.29, 21:34

Re: Проблема с циклическим выполнением запросов

Сообщение question.guy »

Думаю, не лишним было бы привести код, который отвечает за синхронизацию.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Проблема с циклическим выполнением запросов

Сообщение zelenin »

вы очищаете кэш СХЕМЫ таблицы. Схема - это состав таблицы (колонки, индексы итд). На бою ее не надо не очищать не отключать, т.к. строение БД у вас не меняется.
pioneer
Сообщения: 136
Зарегистрирован: 2013.03.10, 23:27

Re: Проблема с циклическим выполнением запросов

Сообщение pioneer »

question.guy писал(а):Думаю, не лишним было бы привести код, который отвечает за синхронизацию.
Вызов из контроллера:

Код: Выделить всё

/**
 * Синхронизация товаров с 1С.
 */
public function actionSynchronize()
{
    $goodSync = new Good();
    $goodSync->synchronize();

    $this->render('sync-success', array(
        'new_goods'=>$goodSync->new_goods_1c,
        'old_goods'=>$goodSync->old_goods_1c,
        'sync_time'=>$goodSync->sync_time_1c
    ));
}
Модель Товара:

Код: Выделить всё

/**
 * Синхронизация товаров с 1С.
 * Если товар уже существует в базе - обновляем его характеристики, иначе - добавляем новый.
 * После синхронизации показываем затраченное время на синхронизацию и кол-во добавленных/обновленных записей.
 */
public function synchronize()
{
    $connection = Yii::app()->db;

    // очистка из кэша схемы таблицы Товаров
    $connection->schema->getTable('catalog_good', true);

    $time_start = time();
    $file = Yii::app()->getBaseUrl(true) . '/1c/goods.xml';

    $dom = new DOMDocument();
    $dom->load($file) or die($file.' - файл отсутствует либо нет прав доступа');

    $xmlPath = new DOMXPath($dom);
    $arrNodes = $xmlPath->query('//GOODS/ITEM');

    $i_new = 0; // счетчик новых товаров
    $i_old = 0; // счетчик изменных товаров
    $data = array();
    
    // в цикле выполняем проход по строкам из xml, получая нужные нам атрибуты товара
    foreach($arrNodes as $item) {
        $data['1c_id']        = $item->getAttribute('ID');
        $data['quantity']        = $item->getAttribute('Количество');
        $data['country']        = $item->getAttribute('СтранаПроизводитель');
        // ...и другие

        // последний раз даже пытался решить свою проблему транзакциями
        $transaction = $connection->beginTransaction();

        try
        {
            $select = $connection->createCommand()
                ->select('*')
                ->from('catalog_good')
                ->where('1c_id=:id', array(':id'=>$data['1c_id']))
                ->limit(1)
                ->query();

            // если такой товар уже присутствует в БД - просто обновляем его характеристики
            if($select->rowCount)
            {
                $connection->createCommand()
                    ->update('catalog_good', array(
                            '1c_id'             => $data['1c_id']
                            'quantity'          => $data['quantity'],
                            'country'        => $data['country'],
                            // ...и другие
                        ), '1c_id=:id', array(':id'=>$data['1c_id']));

                    $i_old++;
            }
            // иначе - добавляем новый товар в БД
            else
            {
                $connection->createCommand()
                    ->insert('catalog_good', array(
                            '1c_id'             => $data['1c_id'],
                            'quantity'          => $data['quantity'],
                            'country'        => $data['country'],
                            // ...и другие
                    ));

                $i_new++;
            }

            $transaction->commit();
        }
        catch(Exception $e)
        {
            $transaction->rollback();
        }

        $data = array();
    }

    $this->new_goods_1c = $i_new;
    $this->old_goods_1c = $i_old;
    $this->sync_time_1c = time() - $time_start;
}
zelenin писал(а):вы очищаете кэш СХЕМЫ таблицы. Схема - это состав таблицы (колонки, индексы итд). На бою ее не надо не очищать не отключать, т.к. строение БД у вас не меняется.
Спасибо за разъяснения предназначения этого параметра!
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Проблема с циклическим выполнением запросов

Сообщение zelenin »

кэширования у вас нет. имхо дело в какой-то ошибке, после которой транзакция откатывается.

Код: Выделить всё

catch(Exception $e)
        {
            $transaction->rollback();
        } 
поменяйте на

Код: Выделить всё

catch(Exception $e)
        {
        $message = $e->getMessage(); // сообщение куда-нибудь либо отправьте мылом, либо выведите в браузер, либо залогируйте 
            $transaction->rollback();
        }

 
pioneer
Сообщения: 136
Зарегистрирован: 2013.03.10, 23:27

Re: Проблема с циклическим выполнением запросов

Сообщение pioneer »

zelenin писал(а):кэширования у вас нет. имхо дело в какой-то ошибке, после которой транзакция откатывается.

Код: Выделить всё

catch(Exception $e)
        {
            $transaction->rollback();
        }
поменяйте на

Код: Выделить всё

catch(Exception $e)
        {
        $message = $e->getMessage(); // сообщение куда-нибудь либо отправьте мылом, либо выведите в браузер, либо залогируйте 
            $transaction->rollback();
        }

Дело в том, что данная проблема появилась еще до внедрения мною транзакций. И вот сам прикол в том, что как я уже и упомянул для одной выгрузки все проходит гладко (я вижу, что счетчики соответствуют числу строк в xml-файле), а для последующей - счетчики ни чуть не меняются, и только когда ждешь некторое время - например, 5 минут - и пытаешься снова синхронить выгрузку - тогда все срабатывает должным образом (уже для новой выгрузки). Короче говоря, создается такое впечатление, что система каким-то чудным образом "запоминает" считываемый файл на некоторое время и после появления в нужной папке файла с таким же именем, но уже другим содержанием отказывается некоторое время "понимать", что это новый файл и нужно работу делать по новой) В общем, объяснил как мог, но первое что я подумал - это какое-то там кеширование...
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Проблема с циклическим выполнением запросов

Сообщение zelenin »

разбираться даже лень - реализация убогая.
прочтите файл, сформируйте массив из товаров из xml, проиндексировав по 1c_id, возьмите все 1c_id, сделайте запрос вида select id from goods where id in ('. implode(', ', $1c_ids) . '); - в результате получим массив id, которые надо апдейтить. Отфильтровали первоначальный массив на две части - проапдейтить и вставить. Вставить пачку можно одним запросом. Апдейтить придется перебором. Так получится быстрее и нагляднее. Плюс пишите в логи результаты запросов и все цифры, типа "Из xml получили 1000 товаров", "300 проапдейтить, 700 вставить", "Вставка произошла успешно" итд.
Плюс конечно же это должна быть консольная команда, а не веб-экшн.
Ответить