【问题标题】:How should I program this ratings feature to minimize concurrency issues?我应该如何编程此评级功能以最大限度地减少并发问题?
【发布时间】:2015-12-11 16:49:13
【问题描述】:

我正在为 Symfony 应用程序编写一个功能,允许用户提交产品评级。我在每次评分后计算产品评分的平均值,这样我就不需要在每次需要平均评分时运行可能很昂贵的AVG() 查询。

这是一个计算平均评分并保存的简单函数:

public function calculateAndSaveAverageRating(Product $product)
{
    // Run the SUM() query and return a float containing the average,
    // or null if there are no ratings for the product.
    $calculatedAverage = $this
        ->em
        ->getRepository('AppBundle:Product')
        ->findAverageRating($product);

    // Lookup an existing ProductRatingAverage entity if it exists. This
    // stores the average value of ratings for each product. Returns null
    // if there is no existing entity.
    $existingAverageEntity = $this
        ->em
        ->getRepository('AppBundle:ProductRatingAverage')
        ->findOneBy(array('product' => $product));

    // Save the calculated average if we got a non-null value. Otherwise
    // there are no ratings for this product, so delete the existing
    // average entity if it exists.
    if ($calculatedAverage) {
        // If we have an existing average entity, update it. Otherwise
        // create a new one and store the average.
        if ($existingAverageEntity) {
            $existingAverageEntity->setAverage($calculatedAverage);
        } else {
            $existingAverageEntity = new ProductRatingAverage();
            $existingAverageEntity->setProduct($product);
            $existingAverageEntity->setAverage($calculatedAverage);
            $this->em->persist($existingAverageEntity);
        }
    } else {
        if ($existingAverageEntity) {
            $this->em->remove($existingAverageEntity);
        }
    }

    $this->em->flush();
}

但是这里有一些并发问题。这是其中的两个:

  1. 如果两个用户同时提交没有先前评分(或非常接近)的产品评分,则此代码将尝试为同一产品创建两个平均评分实体,但只能有一个(数据库唯一约束)。
  2. 如果两个用户同时(或非常接近)为具有先前评分的产品提交评分,则此代码可能会从计算的平均值中排除其中一个评分。

我可以采取不同的方法:在运行 AVG() 查询的查询前面放置一个过期缓存,并让它每 1 小时或其他时间过期。但是,我遇到了同样的问题:如果两个访问者同时触发缓存刷新,就会出现同样的并发问题。

我应该如何设计这段代码以尽量减少并发问题?

【问题讨论】:

    标签: php symfony doctrine


    【解决方案1】:

    并发的解决方案通常是锁定机制。有时只需要一个行锁,而其他时候锁整个表。第一个事务应用表锁,之后用于搜索或修改数据的其余事务保持等待,直到第一个事务显式执行解锁。我建议您阅读以下链接http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/transactions-and-concurrency.html#locking-support

    【讨论】:

      猜你喜欢
      • 2014-08-27
      • 1970-01-01
      • 2012-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-04
      • 2020-02-05
      • 2021-11-26
      相关资源
      最近更新 更多