Привет! Пробую коротко изложить суть проблемы. Если создал тему не в том разделе, прошу простить и перенести. Есть приложение работающее на древней конфигурации и выполняющее следующие операции: 1) Чтение из нескольких таблиц. 2) Проверка и сравнение данных и обработка информации. 3) Запись в таблицу базы данных - действий, логов. 4) Повторное чтение из нескольких таблиц для отображения обновленной информации. Также запущен php-демон, который выполняет операции каждые 2 секунды. Конфигурация: - php 5.4.45 mysqli - mysql 5.5.57 - nginx 1.2.1 - Тип таблиц InnoDB Кусок кода по записи логов: PHP: <? //- $id = айди ( НЕ autoincrement ) //- $log = массив действий //- Пример: $log = array ( 'time' => date("H:i:s"), 'login' => 'Василий', 'action' => 'Изменение цены товара -1 рубль' ); //- $log = array ( 'time' => date("H:i:s"), 'login' => 'Анастасия', 'action' => 'Изменение цены товара -1 рубль' ); //- $log = array ( 'time' => date("H:i:s"), 'login' => 'Demon', 'action' => 'Изменение цены товара -1 рубль' ); $sql = array(); //- Перебираем массив действий foreach ( $log as $l ) { $sql[] = array( $id, serialize( $l ) ); } unset( $l, $log ); if ( !empty( $sql ) ) { //- multi insert $db->query("INSERT INTO `logs` ( `id`, `action` ) VALUES ?v ",array( $sql ) ); } unset( $sql ); ?> Всё это дело корректно работает, когда операцию выполняет 1 человек и/или demon, но когда происходит по 5 записей в секунду от 3 и более пользователей, изредка происходит баг. Пример: - Цена товара 10 рублей. В логах вижу: - 23:00:00 Василий изменил цену -1 рубль. - 23:00:00 Итоговая цена 9 рублей ( тут все ок ). - 23:00:05 Анастасия изменила цену -1 рубль. - 23:00:05 Demon изменил цену -1 рубль. - Итоговая цена 8 рублей ( а тут словили глюк, два запроса в одно время и лог "влез" в действие чужого пользователя ) Пример показан с товарами, мне показалось, что так будет легче понять о чем я пишу. Ещё раз о проблеме: Если 10 разных пользователей выполняют одно и тоже действие, то это действие может происходить в одно и тоже время. В связи с чем ловлю баг, когда информация некорректно обрабатывается. Вопросы: - Какие механизмы можно использовать для блокировки ? Читал немного про lock tables. - Нужно учесть, что данные таблицы учавствуют не только в этом модуле, а потому не хотелось бы получить ошибки в других модулях, если таблицы будут заблокированы. - Куда копать и рыть туннель? Спасибо! P.S. Сам Демон и функционал тестировался длительное время. Создавалось условно 100 действий по 6000 возможных операций. Каждые 2 секунды демон выбирал 100 раз по 1 из 6000 возможных и ПОДХОДЯЩИХ по условию операций и совершал ее. Вся работа скрипта в пределах нормы, около 1 секунды. Но при этом стоит заметить, что операции таки достаточно тяжелые. На самом деле там выполняются более сложные операции, чем просто изменение стоимости.
в куске кода совсем нет вычисления Итоговая цена. Да я думаю оно там и не нужно. И в лог не пишите . а итоговую цену на любой момент можно вычислить суммируя все изменения по товара к начальной цене с любым условием. в том числе - на определенную дату/время
Смысл в том, что в моем случае могут 50 пользователей выполнить запрос, действия которого изменяют одни и те же данные. Загвоздка в том, что при наличии нескольких одновременных запросов происходят глюки, не последовательная запись логов, как пример. Как и что сделать, чтобы эти данные корректно и по очереди выполнялись ?
Транзакции подключены по дефолту уровень изоляции REPEATABLE-READ Как-то влияет на дублирование данных тот факт, что такой же код выполняет отдельный процесс ? я про демона. в общем проблему пока так и не решил, даже не знаю, стоит обновлять пых, а вместе с тем и все остальное? Долго черд его дери)
Попробовал использовать транзакции. Имеем два случая: 1) Когда данные изменяЮт пользователи. 2) Эти же данные изменяет демон (частоту с 2-х сек снизил до 1-й сек ) Вид сбоку: 1) SET autocommit=0 2) START TRANSACTION 3) много кода. много кода. много кода (без ошибок конечно же) 4) COMMIT Все равно проскакивают одновременно изменение данных. Пробовал всё это дело совместить с блокировкой всех используемых в модуле таблиц, проблему это не исправило, но добавило Deadlock found when trying to get lock; try restarting transaction Конечно всё обернуть нужно в try и повторить запрос.. только вот самой проблемы это не исправило. Т.е. данные как дублировались ( точнее действия ), так и продолжают дублироваться, только теперь с ошибкой ( время от времени ). Что-то кажется интересное, но сейчас бы чего по проще, а не переписывать 10к строк кода и вникать в ещё столько же...
В общем, кажется проблему решил с помощью транзакций и блокировки строк, а не всей таблицы. Несколько критических запросов теперь имеют вид SELECT `id` FROM `table` WHERE ? LIMIT 1 FOR UPDATE