Doctrine: ON DUPLICATE KEY UPDATE

后端 未结 9 1152
有刺的猬
有刺的猬 2020-12-18 19:43

How can I write an INSERT doctrine query with option ON DUPLICATE KEY UPDATE?

9条回答
  •  我在风中等你
    2020-12-18 20:22

    You can't. It's not supported by Doctrine right now.

    What you could do is to imitate what MySQL does by checking if the entity exists and update/create it accordingly:

    $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);
      }
    });
    

    If the record exists PESSIMISTIC_WRITE makes sure that it's not updated by anyone (e.g., other threads) while we're updating it.

    Although you need to check for the entity's existence on every update, it's a simple reproduction of "update if existing and create if not".

    As pointed out in the comments this does not prevent a race condition if the record doesn't exist: If a row with the same key(s) gets inserted between the select and the insert you're running into a duplicate key exception.

    But given the constraints that this needs to be DB independent and thus written using Doctrine and not using native SQL it may help in some cases.

    References:

    • Database Administrators: Putting a Select statement in a transaction
    • MySQL Reference Manual: Locking Reads (SELECT ... FOR UPDATE)
    • Doctrine 2 ORM documentation: Transactions and Concurrency
    • Stackoverflow: Doctrine2 ORM select for update

提交回复
热议问题