Используя Symfony 4 с доктриной, я хочу сохранить просмотры страниц для одного объекта Program в базе данных. Я хочу сохранить это в базе данных, потому что хочу дать некоторым пользователям права просматривать эти числа. Что я сделал, так это добавил свойство к сущности следующим образом:
Program.php
/**
* @ORM\Column(type = "integer", nullable=true)
*/
private $pageViews;
/**
* @return mixed
*/
public function getPageViews()
{
return $this->pageViews;
}
/**
* @param mixed $pageViews
*/
public function setPageViews($pageViews)
{
$this->pageViews = $pageViews;
}
А в моем ProgramController.php в функции showProgram
//...
$program->setPageViews($program->getPageViews()+1);
$em->persist($program);
$em->flush();
Это работает и добавляет 1 к существующему числу при каждом обновлении страницы. Мой вопрос: это приемлемый метод или есть более быстрые / лучшие альтернативы? И это снижает производительность или это незначительно?
Вы можете использовать doctrines dql lang, чтобы избежать гидратации сущностей, так что это будет намного быстрее, как это - ОБНОВЛЕНИЕ MyProject \ Model \ Program p SET p.pageViews = p.pageViews + 1






Поскольку вам действительно не нужна сущность, вы можете сделать это напрямую с помощью SQL, используя соединение Doctrine:
$connection = $this->getDoctrine()->getConnection();
$connection->executeUpdate('UPDATE page_view_counter SET page_view = page_view+1;');
или используя заранее подготовленный оператор:
$connection = $this->getDoctrine()->getConnection();
$statement = $connection->prepare(
'UPDATE programs SET page_views = page_views + 1 WHERE programs.id = :id'
);
$statement->bindValue('id', $id);
$statement->execute();
Это немного ускорит процесс, если не использовать некоторые из более сложных функций ORM, которые вам не нужны в вашем случае.
Другой альтернативой для ускорения работы может быть переключение технологий, например хранение данных в кеше, таком как redis. Будет ли это действительно улучшать производительность (особенно при более высокой нагрузке), необходимо будет проверить с помощью какого-либо измерительного инструмента, такого как JMeter.
Мне действительно нужна сущность, потому что на показываемой мной странице мне нужно показать программные переменные. Так что, я думаю, в этом случае мое решение или решение Сида могло бы быть лучше?
Да, по крайней мере, для начала. Вы все равно должны быть осторожны, так как ваш код может создавать условия гонки. Если пользователи A и B загружают сайт примерно в одно и то же время, скажем, 100 page_views, они оба загружают это значение и увеличивают его. Затем они сохранят свое значение, и поэтому независимо от того, какой из них сохраняет значение последним, счетчик, вероятно, будет говорить 101, а не 102. С моим кодом этого не произойдет, потому что каждый запрос обновляет значение в базе данных напрямую, а не загружает это первое. Если вы не возражаете против этого небольшого отклонения, ваше решение должно работать нормально.
Кстати, подход Сида будет иметь тот же недостаток. Поскольку он также загружает значение в объект, обновляет его, а затем сохраняет новое состояние объекта в базе данных. Единственный способ обойти это - сделать обновление атомарным, не извлекая его сначала, а вместо этого выполняя +1 непосредственно в базе данных с помощью SQL.
Очевидно, что прямая отправка SQL-запроса - безусловно, лучший вариант. Этот запрос достаточно прост, чтобы избежать проблем связи между различными СУБД. Будем надеяться, что у вас нет полей и таблицы с неправильным именем, которую необходимо заключить в обратные кавычки или скобки.
@dbrumann, еще кое-что; есть ли способ привязать параметр к этому SQL? Я пытаюсь сохранить просмотры страниц для каждой отдельной программы, поэтому сейчас я пытаюсь сделать что-то вроде этого: $connection->executeUpdate('UPDATE programs SET page_views = page_views+1 WHERE programs.id is :id; '); Однако я не могу привязать параметр, чтобы использовать его в запросе.
Да, DBAL также поддерживает параметры: doctrine-project.org/projects/doctrine-dbal/en/2.8/reference /…. Я добавил пример к своему ответу
public function addPageViews() { ++$this->pageViews; }может быть немного быстрее, кроме того, я не вижу, что можно оптимизировать