php websocket 棘轮不从学说中获取最新数据
php websocket ratchet doesn't fetch newest data from doctrine
我刚刚在弄乱 WebSocket 应用程序时发现了一个非常有趣的事实,我现在正在使用 Symfony 4.1 和 https://github.com/GeniusesOfSymfony/WebSocketBundle(基于 PHP Ratchet 构建)。
我想使用 $repository->find(2);
定期从 MySQL 数据库中获取最新数据以进行测试,但它总是返回相同的结果,即使我在订阅 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 得到了?
实际上我自己设法解决了这个问题。
Doctrine 的 EntityManager find(...)
方法实际上将结果缓存在实体名称和条目 ID 下名为 $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 生命周期。一个请求进来,一个响应出去,然后一切都关闭了。下一个请求从零开始。
如果你使用 websocket,这永远不会发生,PHP 永远运行(不是真的,但理想情况下),并且棘轮响应事件。
(OFF: 查看 PHP-PM...他们已经能够达到请求/s 的急剧增加,因为他们颠覆了 PHP 生命周期)。
锁定模式是一种解决方案,但您也可以调用 $em->refresh($entity)
,这会触发从数据库重新加载。
我刚刚在弄乱 WebSocket 应用程序时发现了一个非常有趣的事实,我现在正在使用 Symfony 4.1 和 https://github.com/GeniusesOfSymfony/WebSocketBundle(基于 PHP Ratchet 构建)。
我想使用 $repository->find(2);
定期从 MySQL 数据库中获取最新数据以进行测试,但它总是返回相同的结果,即使我在订阅 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 得到了?
实际上我自己设法解决了这个问题。
Doctrine 的 EntityManager find(...)
方法实际上将结果缓存在实体名称和条目 ID 下名为 $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 生命周期。一个请求进来,一个响应出去,然后一切都关闭了。下一个请求从零开始。
如果你使用 websocket,这永远不会发生,PHP 永远运行(不是真的,但理想情况下),并且棘轮响应事件。
(OFF: 查看 PHP-PM...他们已经能够达到请求/s 的急剧增加,因为他们颠覆了 PHP 生命周期)。
锁定模式是一种解决方案,但您也可以调用 $em->refresh($entity)
,这会触发从数据库重新加载。