Php websocket ratchet не извлекает новейшие данные из доктрины

Довольно интересный факт, который я только что обнаружил, когда испортил приложение WebSocket, которое я сейчас создаю с использованием Symfony 4.1 и https://github.com/GeniusesOfSymfony/WebSocketBundle (который построен на PHP Ratchet).

Я хотел периодически получать новейшие данные из базы данных MySQL для целей тестирования с использованием $repository->find(2);, но он всегда возвращал один и тот же результат, хотя я менял данные во время подписки на канал WebSocket.

После многих часов возни с кодом и слез я обнаружил, что Doctrine по какой-то причине кэширует результаты (или, как мне кажется, именно так).

Чтобы проверить свою теорию, я создал сервис, который обрабатывает выборку из базы данных со следующим кодом:

/**
 * @return mixed
 * @throws \Doctrine\DBAL\DBALException
 */
public function fetchNewest()
{
    $stmt = $this->em->getConnection()->prepare('SELECT * FROM test WHERE id=2');
    $stmt->execute();

    return $stmt->fetch();
}

и по какой-то причине это сработало. Может ли кто-нибудь объяснить, почему метод find(2) не дает новейших данных, в то время как необработанный SQL дает?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
0
549
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Мне и самому удалось в этом разобраться.

Метод Doctrine EntityManager find(...) фактически кэширует результат внутри частного поля с именем $unitOfWork под именем объекта и идентификатором записи.

Каждый раз, когда вы пытаетесь найти что-то с помощью $em->find(...), и это удается, результат сохраняется внутри $this->unitOfWork, и если вы снова попытаетесь получить то же самое, он просто загрузится из кеша.

   // Check identity map first
    if (($entity = $unitOfWork->tryGetById($sortedId, $class->rootEntityName)) !== false) {
        if ( ! ($entity instanceof $class->name)) {
            return null;
        }

        switch (true) {
            case LockMode::OPTIMISTIC === $lockMode:
                $this->lock($entity, $lockMode, $lockVersion);
                break;

            case LockMode::NONE === $lockMode:
            case LockMode::PESSIMISTIC_READ === $lockMode:
            case LockMode::PESSIMISTIC_WRITE === $lockMode:
                $persister = $unitOfWork->getEntityPersister($class->name);
                $persister->refresh($sortedId, $entity, $lockMode);
                break;
        }

        return $entity; // Hit!
    }

Это случай "symfony/orm-pack": "^1.0" и "doctrine/orm": "^2.5.11"

Редактировать:

Вызов $repository->find(2, LockMode::NONE); решает проблему.

Ответ принят как подходящий

Это правильное и ожидаемое поведение ORM. Это способ облегчить нагрузку на базу данных.

Это хорошо задокументировано, но в большинстве случаев мы просто переходим к примерам и пропускаем их. :)

Обычно вы не замечаете этого в приложении из-за жизненного цикла PHP. Приходит запрос, отключается ответ и все отключается. Следующий запрос начинается с чистого листа.

Если вы используете веб-сокет, этого никогда не произойдет, PHP просто работает вечно (не совсем, но в идеале), а храповик реагирует на события.

(ВЫКЛ: проверьте PHP-PM ... они смогли добиться резкого увеличения количества запросов, потому что они подорвали жизненный цикл PHP).

Режим блокировки - это решение, но вы также можете вызвать $em->refresh($entity), который запускает перезагрузку из базы данных.

Обновлено: документы https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/working-with-objects.html#entities-and-the-identity-map

Да, забавно, что я пропустил такое поведение, работая с этими небольшими HTTP-запросами, лол. Спасибо!

Milan Vlach 29.07.2018 17:56

Я не уверен, но думаю, что сначала заметил это у пользователя rabbitmq. Действительно легко пропустить в простом приложении. :)

Padam87 29.07.2018 18:06

Другие вопросы по теме