Php Doctrine2 ORM选择进行更新
您能否建议一种方法,如何使用条令实施Php Doctrine2 ORM选择进行更新,php,mysql,concurrency,doctrine,Php,Mysql,Concurrency,Doctrine,您能否建议一种方法,如何使用条令实施选择更新 我需要读取一个计数器值,然后在PHP代码中使用它,并在其他人(来自另一个进程)使用相同的值之前立即增加该值。锁定支持 第2条原则适用于实体: <?php use Doctrine\DBAL\LockMode; use Doctrine\ORM\OptimisticLockException; $theEntityId = 1; $expectedVersion = 184; try { $entity = $em->find(
选择更新
我需要读取一个计数器值,然后在PHP代码中使用它,并在其他人(来自另一个进程)使用相同的值之前立即增加该值。锁定支持
第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!";
}
然后
$em->getConnection()->exec('UNLOCK TABLES;');
显然,Doctrine 2在共享模式下使用锁,并对MySQL使用悲观读锁,这与SELECT for UPDATE不同 从当前稳定版本的来源来看,似乎没有本地方式 在条令中这样做的可能性(我不知道条令团队为什么选择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();
警告来自谷歌的任何人
如果对现有实体使用条令的悲观写锁,
然后,锁定后将不会重新蚀刻该实体
所以这个代码:
$entity = $this->em->find(Product::class, $id);
// use the product for some read only code
// Later, Need to update product
$this->em->lock($entity, LockMode::PESSIMISTIC_WRITE);
$entity->setStock($entity->getStock() - 1);
$this->em->flush();
将在SQL中运行类似于以下代码的内容
SELECT t0.id AS id_1, t0.stock AS stock_2 FROM products t0 WHERE t0.id = ?; -- First fetch
SELECT 1 FROM products t0 WHERE t0.id = ? FOR UPDATE; -- Pessimistic lock, no data fetched
UPDATE products SET stock = ? WHERE id = ?; -- Update using old data
这会产生与根本不锁定任何内容相同的结果
您需要在请求锁定的同时再次手动获取实体:
$entity = $this->em->find(Product::class, $id);
// use the product for some read only code
// Need to update product
$this->em->find(Product::class, $entity->getId(), LockMode::PESSIMISTIC_WRITE); // You dont need the return value, doctrine will update all loaded entities
$entity->setStock($entity->getStock() - 1);
$this->em->flush();
这是确保doctrine在获得锁后将更新其缓存以及实体对象本身的唯一方法
$em->lock()
和$em->refresh()
在这里都不起作用。MySQL的SELECT FOR UPDATE与您的原生SQL解决方案有很大不同:它使用一个“特殊”行级锁,它只与其他SELECT FOR UPDATE语句(以及其他,请参阅MySQL文档)一起工作,使用事务时不需要解锁(请参阅:)我刚刚检查了我的SQL日志,在使用悲观写入
锁定模式时,条令2确实使用了选择更新
。刚刚重新检查了条令源,是的,悲观写入实际上生成了选择更新,很好!
$entity = $this->em->find(Product::class, $id);
// use the product for some read only code
// Later, Need to update product
$this->em->lock($entity, LockMode::PESSIMISTIC_WRITE);
$entity->setStock($entity->getStock() - 1);
$this->em->flush();
SELECT t0.id AS id_1, t0.stock AS stock_2 FROM products t0 WHERE t0.id = ?; -- First fetch
SELECT 1 FROM products t0 WHERE t0.id = ? FOR UPDATE; -- Pessimistic lock, no data fetched
UPDATE products SET stock = ? WHERE id = ?; -- Update using old data
$entity = $this->em->find(Product::class, $id);
// use the product for some read only code
// Need to update product
$this->em->find(Product::class, $entity->getId(), LockMode::PESSIMISTIC_WRITE); // You dont need the return value, doctrine will update all loaded entities
$entity->setStock($entity->getStock() - 1);
$this->em->flush();