7

我需要用学说锁定整个表(而不是单行),如果可能的话,我想在没有本机查询的情况下这样做。

悲观锁定的文档仅描述了如何通过这些方法锁定特定实体:

  • 实体管理器#find
  • 实体管理器#lock
  • 查询#setLockMode

我有一个事务需要插入一行,其值取决于表中其余行的值,因此我需要防止两个事务同时在该表上执行。

我正在使用显式事务划分,它应该可以很好地与锁定配合使用(根据上面的文档)。

注意:在这种情况下,乐观锁定还不够好,我负担不起重试事务。此外,查询不应该很慢,因此性能不是问题。

编辑:我举个例子。想象一下,您想手动构建一个 auto_increment,并且您必须从表中选择 max() 以获取上一个结果才能插入下一个结果。您必须确保没有两个事务尝试插入相同的值,以防它们同时选择 max()。

当 auto_increment 不好时,我正在寻找此问题的通用解决方案,例如使用字符串、多列、散列或您必须对前一个行集进行的任何计算。

锁定是一个可靠的解决方案,与乐观锁定不同,您不必重试错误。

那么,有没有办法在学说中使用表锁定?

4

3 回答 3

4

到目前为止,按照建议,我尝试了这个:

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

// calculate $new_number...

// persist $new_number on table_name...
$table_name->setCalculatedNumber($new_number);
$em->persist($table_name);
$em->flush();

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

我用 JMeter 对其进行了测试,并且锁定在负载很重(16 个请求/秒)的情况下无法正常工作。跟踪显示其他实例在明确放弃之前获得了锁。问题(正如 Jens 所建议的)是 flush() 隐式以 START TRANSACTION 开头,这会删除表锁。使用本机更新为我解决了这个问题:

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

// calculate $new_number...

// persist $new_number on table_name...
$em->getConnection()->executeUpdate("UPDATE table_name set ...;");    

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

需要尾随 refresh() 以使计算出的数字在后续查询结果中可用

于 2015-04-08T19:06:21.870 回答
2

可能被 Doctrine2 ORM 复制更新选择

下面是一些相关代码:

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

    // do the work

    $em->flush();
} catch(OptimisticLockException $e) { 
    echo "Sorry, but someone else has already changed this entity. Please apply the changes again!";
}

LockMode::OPTIMISTIC 参数可能会提供您需要的内容。

于 2013-12-11T21:14:24.480 回答
1

通过查看 Doctrine 2.x 中的文档,我认为没有支持锁定整个表的方法。您当然可以尝试通过 Doctrine 单独锁定所有记录,但这会很麻烦并且不是一个好主意。

相反,我会使用 Doctrine 实体管理器在数据库上执行原始 SQL ......

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

然后在你完成更新后......

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

编辑:

来自关于表锁的MySQL 文档...

  • 持有锁的会话可以读写表。

  • 只有持有锁的会话才能访问该表。在释放锁之前,没有其他会话可以访问它。

  • 当持有 WRITE 锁时,其他会话对表的锁请求会阻塞。

我认为这里的第二点是关键,只有您的会话可以读/写该表。

于 2012-07-03T12:09:30.510 回答