Doctrine2 ORM для обновления
Пожалуйста, можете ли вы предложить мне какой-то подход, как реализовать SELECT FOR UPDATE
с помощью Doctrine?
Мне нужно прочитать значение счетчика, использовать его в PHP-коде и сразу увеличить значение до того, как кто-то другой (из другого процесса) будет использовать одно и то же значение.
Ответы
Ответ 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);
Кроме того, вы должны использовать оператор внутри транзакции, чтобы заставить его работать.