学说:重复主题更新

Leo*_*rdo 13 mysql pdo doctrine on-duplicate-key

如何INSERT用选项编写学说查询ON DUPLICATE KEY UPDATE

小智 15

对于Symfony 2 使用原始sql:

$em->getConnection()->prepare("INSERT INTO table SET 
    some_fields = "some data", created_at = NOW() 
    ON DUPLICATE KEY UPDATE
    some_fields = "some data", updated_at = NOW()
")->execute();
Run Code Online (Sandbox Code Playgroud)

  • 我不喜欢这种方法,因为它打破了Doctrine给我的数据库独立性.但它仍然比每次检查实体是否已经存在都需要进行数据库获取更好,因为大多数情况下它都会存在.更新将比插入更常见. (2认同)
  • 这是迄今为止我见过的唯一没有竞争条件的解决方案 (2认同)

DrC*_*sos 7

问题是这是MySQL特有的问题所以它不会被Doctrine直接涵盖.

正如提到的评论,您需要为此编写RawSQL查询.这将是最简单的方法.

如果您希望它更复杂,并且真正与数据库无关,请查看事件及其可能性.在执行实际查询之前,您可以检查是否存在,如果存在,则相应地执行操作.

ORM/PHP独立方式是编写处理此问题数据库端的存储过程/触发器.

  • @StanislavPalatnik我发现REPLACE的唯一参考是MySQL和SQLite的保留关键字列表. (3认同)

flu*_*flu 6

你不能。目前 Doctrine 不支持它。

您可以做的是通过检查实体是否存在并相应地更新/创建它来模仿 MySQL 的操作:

$em = $this->getEntityManager();

// Prevent race conditions by putting this into a transaction.
$em->transactional(function($em) use ($content, $type) {
  // Use pessimistic write lock when selecting.
  $counter = $em->createQueryBuilder()
    ->select('MyBundle:MyCounter', 'c')
    ->where('c.content = :content', 'c.type = :type')
    ->setParameters(['content' => $content, 'type' => $type])
    ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE);
    ->getQuery()
    ->getResult()
  ;

  // Update if existing.
  if ($counter) {
    $counter->increase();
  } else {
    // Create otherwise.
    $newCounter = new Counter($content, $type, 1);
    $em->persist($newCounter);
  }
});
Run Code Online (Sandbox Code Playgroud)

如果记录存在,PESSIMISTIC_WRITE请确保在我们更新它时它不会被任何人(例如其他线程)更新。

尽管您需要在每次更新时检查实体是否存在,但这只是“如果存在则更新,如果不存在则创建”的简单再现。

正如评论中指出的,如果记录不存在,这不会阻止竞争条件:如果在选择和插入之间插入具有相同键的行,则会遇到重复键异常。

但考虑到这需要独立于数据库的限制,因此使用 Doctrine 编写而不是使用本机 SQL,这在某些情况下可能会有所帮助。

参考:

  • 由于您无法锁定不存在的行,因此您的解决方案仍然会遇到竞争条件。这意味着如果在“SELECT”之后但在“INSERT”之前插入具有相同键的行,您将捕获错误/异常。 (2认同)