Подтвердить что ты не робот

Doctrine2 ORM для обновления

Пожалуйста, можете ли вы предложить мне какой-то подход, как реализовать SELECT FOR UPDATE с помощью Doctrine?

Мне нужно прочитать значение счетчика, использовать его в PHP-коде и сразу увеличить значение до того, как кто-то другой (из другого процесса) будет использовать одно и то же значение.

4b9b3361

Ответ 1

Поддержка блокировки

Doctrine 2 реализует Поддержка блокировки для объектов:

<?php
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\OptimisticLockException;

$theEntityId = 1;
$expectedVersion = 184;

try {
    $entity = $em->find('User', $theEntityId, LockMode::OPTIMISTIC, $expectedVersion);

    // do the work

    $em->flush();
} catch(OptimisticLockException $e) {
    echo "Someone else has already changed this entity. Apply the changes again!";
}

Нативный sql

Кроме того, вы можете сделать это, чтобы выполнить необработанный SQL:

$em->getConnection()->exec('LOCK TABLES table_name WRITE;'); //lock for write access

а затем

$em->getConnection()->exec('UNLOCK TABLES;');

Ответ 2

По-видимому, Doctrine 2 использует LOCK IN SHARED MODE с пессимистичной блокировкой чтения для MySQL, которая не совпадает с SELECT FOR UPDATE.

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

Я использовал собственный SQL как обходной путь, который можно сопоставить с традиционными объектами, как это было бы с DQL:

<?php
$rsm = new ResultSetMappingBuilder($this->_em);
$rsm->addRootEntityFromClassMetadata('Model_Record_Delivery', 'u');
$query = $this->_em->createNativeQuery("SELECT * FROM delivery WHERE id = :id FOR UPDATE", $rsm);
$query->setParameter("id", $id);
$result = $query->getOneOrNullResult();

Update

Как отметил Бенджамин, PESSIMISTIC_WRITE - это то, что вы ищете.

С DQL

<?php
$query = $this->em->createQuery('SELECT e
    FROM Application\Model\Entity\MyEntity e
    WHERE e = :id');

$query->setParameter("id", $id);
$query->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE);

Без DQL

<?php
$entity = $em->find('Application\Model\Entity\MyEntity', $id, \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE);

Кроме того, вы должны использовать оператор внутри транзакции, чтобы заставить его работать.