Doctrine2 ORM选择更新

Kub*_*lka 16 php mysql concurrency doctrine

请问您能告诉我如何SELECT FOR UPDATE使用Doctrine 实现一些方法吗?

我需要读取一些计数器值,在PHP代码中使用它并在其他人(来自另一个进程)使用相同值之前立即递增该值.

pau*_*ago 45

显然,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();
Run Code Online (Sandbox Code Playgroud)

更新

正如本杰明指出的那样,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);
Run Code Online (Sandbox Code Playgroud)

没有DQL

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

此外,您必须使用事务中的语句才能使其工作.

  • 我刚刚检查了我的SQL日志,并且在使用`PESSIMISTIC_WRITE`锁定模式时,Doctrine 2确实使用了`SELECT FOR UPDATE`. (13认同)
  • 刚刚重新检查了Doctrine源代码,是的,PESSIMISTIC_WRITE实际上产生了SELECT FOR UPDATE,很好的捕获! (4认同)
  • 这个答案应该被接受了. (2认同)

man*_*nix 6

锁定支持

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!";
}
Run Code Online (Sandbox Code Playgroud)

原生sql

此外,您可以执行它抛出执行原始SQL:

$em->getConnection()->exec('LOCK TABLES table_name WRITE;'); //lock for write access
Run Code Online (Sandbox Code Playgroud)

然后

$em->getConnection()->exec('UNLOCK TABLES;');
Run Code Online (Sandbox Code Playgroud)

  • MySQL的SELECT FOR UPDATE与您的原生SQL解决方案完全不同:它使用"特殊"行级锁定,仅适用于其他SELECT FOR UPDATE语句(以及其他,请参阅mysql文档),并且不需要使用事务进行解锁(请参阅:http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html) (13认同)