主义悲观锁

时间:2015-02-03 23:16:38

标签: php mysql symfony doctrine-orm

情景:

我在Symfony2中实现一个应用程序,每五分钟运行一次命令(cronjob),它通过一个MySql表并在每个记录中,首先读取一个json_array字段,执行一系列计算,最后用新数据保存数组相同的领域。此外,还有一个Web应用程序,用户可以在同一个表中编辑和保存这些数据

为了避免并发,如果命令访问记录,我会做出悲观的锁定,这样,如果用户在那个确切的时刻更改数据必须等到事务结束并且当它完成用户数据时保存。

但是当用户保存数据时,随机存在一个错误,用户数据不会保存,Web应用程序会显示以前的数据,这会告诉我锁定不成功。

我在symfony2命令中编写悲观锁的代码:

    foreach ($this->cisOfferMetaData as $oldCisOfferMeta) {
        // calculate budget used for each timeframe case and save it

        // begin transaction and Lock cisOfferMEta Entity
        $this->em->getConnection()->beginTransaction();
        try {
            $cisOfferMeta = $this->em->getRepository('CroboCisBundle:CisOfferMeta')->find(
                $oldCisOfferMeta->getId(),
                LockMode::PESSIMISTIC_READ
            );

            $budget = $cisOfferMeta->getBudgetOffer();

            foreach (
                generator(CisOfferMeta::getTypesArray(), CisOfferMeta::getTimeframesArray())
                as $type => $timeframe
            ) {
                if (isset($budget[$type][$timeframe]['goal'])) {
                    // if type=budget we need revenue value, if type=conversion, conversions value
                    $budget[$type][$timeframe]['used'] =
                        ($type === 'conversion')
                            ? intval($allTimeframes[$key]['conversions'][$timeframe])
                            : round($allTimeframes[$key]['revenue'][$timeframe], 2);

                    $budget[$type][$timeframe]['percent_reached'] =
                        ($budget[$type][$timeframe]['used'] == 0.0)
                            ? 0.0
                            : round(
                            $budget[$type][$timeframe]['used'] / intval($budget[$type][$timeframe]['goal']) * 100,
                            2
                        );
                }
            }

            $budget['current_conversions'] = $allTimeframes[$key]['conversions'];
            $budget['current_revenue'] = $allTimeframes[$key]['revenue'];

            $cisOfferMeta->setBudgetOffer($budget);

            $this->em->flush($cisOfferMeta);
            $this->em->getConnection()->commit();
        } catch (PessimisticLockException $e) {
            $this->em->getConnection()->rollback();
            throw $e;
        }

    }

我做错了吗?我想自从事务开始直到提交更改,如果用户尝试读取或更新数据,必须等到锁定从被阻止的实体释放。

如果我要在实体中添加版本控制

,那么阅读Doctrine文档并不清楚

1 个答案:

答案 0 :(得分:0)

最后,这段代码正常工作并产生了悲观锁定,问题出现在一个Listener中,它在锁定之前读取数据,然后在锁定释放后刷新而没有更改。