Doctrine 2 - ORM
  1. Doctrine 2 - ORM
  2. DDC-1846

Pessimistic lock does not retreive latest version of entity when entity is already in doctrine cache

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: Git Master
    • Fix Version/s: 2.2.3
    • Component/s: ORM
    • Security Level: All
    • Labels:
      None
    • Environment:
      Mysql 5.5.22-0ubuntu1

      Description

      When setting a pessimistic lock on an entity (e.g. a row lock) and retreiving an entity from the database, Doctrine returns the entity from cache if it has any. When updating a counter on an entity for example, it is important the row is locked, retreived, updated and then unlocked to guarantee the counter keeps in sync. Using $em->clear(); before $em->find(); is a work-around for this problem, but as requested by Benjamin Eberlei on the google groups thread (https://groups.google.com/forum/?fromgroups#!topic/doctrine-user/N8Xop2-XbTY) this bugreport is made to fix this without the need of clear().

      In the next example, if the entity is previously retreived already, find() returns that version instead of retreiving the current version from the database after the rowlock is set. When $em->clear(); can be used to work-around the problem

      // $em instanceof EntityManager
      
      //$em->clear(); // Uncommenting this fixed the problem
      $em->getConnection()->beginTransaction();
      
      try {
      	$entity = $em->find('Entity', $id, LockMode::PESSIMISTIC_WRITE);
      	
      	/* Update some fields, for example, decrease a counter */
      	$entity->setCounter($entity->getCounter() - 1);
      	
      	$em->persist($entity);
      	$em->flush();
      	$em->getConnection()->commit();
      } catch ( \Exception $ex ) {
      	$em->getConnection()->rollback();
      }
      

        Issue Links

          Activity

          Hide
          Jiri Kavalik added a comment -

          Done in DDC-2930

          Show
          Jiri Kavalik added a comment - Done in DDC-2930
          Hide
          Renaud Drousies added a comment -

          Done! See DDC-2929

          Show
          Renaud Drousies added a comment - Done! See DDC-2929
          Hide
          Marco Pivetta added a comment -

          Renaud Drousies Jiri Kavalik can you please open separate (detailed) issues for those problems?

          Show
          Marco Pivetta added a comment - Renaud Drousies Jiri Kavalik can you please open separate (detailed) issues for those problems?
          Hide
          Jiri Kavalik added a comment -

          When this is revived, I noticed that $em->lock($entiy, PESSIMISTIC_WRITE); doesn't refresh too. If it is not supposed to, it might be noted in documentation or in http://docs.doctrine-project.org/en/2.0.x/reference/transactions-and-concurrency.html

          Show
          Jiri Kavalik added a comment - When this is revived, I noticed that $em->lock($entiy, PESSIMISTIC_WRITE); doesn't refresh too. If it is not supposed to, it might be noted in documentation or in http://docs.doctrine-project.org/en/2.0.x/reference/transactions-and-concurrency.html
          Hide
          Renaud Drousies added a comment - - edited

          Sorry to comment on a closed ticket, but this is also happening when setting a pessimistic lock on Query objects (unless you set the Query::HINT_REFRESH hint)

          Example:

                  $em->beginTransaction();
                  try {
                      $bar = $em->createQuery('SELECT b FROM Foo:Bar b WHERE b.id = :id')
                                  ->setParameter('id', 150)
                                  ->getSingleResult();
                      var_dump($bar->getAmount()); // Yields some positive value
                      $bar->setAmount(0);
                      $bar = $em->createQuery('SELECT b FROM Foo:Bar b WHERE b.id = :id')
                                  ->setParameter('id', 150)
                                  ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE)
                                  // ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true)
                                  ->getSingleResult();
                      var_dump($bar->getAmount()); // Yields 0
          
                      $em->flush();
                      $em->commit();
                  } catch (\Exception $e) {
                      $em->rollback();
                  }
          

          Is this the desired behaviour when using a query, or is it related to this bug?

          (Tested on 2.4.0 and 2.4.1)

          Show
          Renaud Drousies added a comment - - edited Sorry to comment on a closed ticket, but this is also happening when setting a pessimistic lock on Query objects (unless you set the Query::HINT_REFRESH hint) Example: $em->beginTransaction(); try { $bar = $em->createQuery('SELECT b FROM Foo:Bar b WHERE b.id = :id') ->setParameter('id', 150) ->getSingleResult(); var_dump($bar->getAmount()); // Yields some positive value $bar->setAmount(0); $bar = $em->createQuery('SELECT b FROM Foo:Bar b WHERE b.id = :id') ->setParameter('id', 150) ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) // ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true ) ->getSingleResult(); var_dump($bar->getAmount()); // Yields 0 $em->flush(); $em->commit(); } catch (\Exception $e) { $em->rollback(); } Is this the desired behaviour when using a query, or is it related to this bug? (Tested on 2.4.0 and 2.4.1)

            People

            • Assignee:
              Benjamin Eberlei
              Reporter:
              Bram Klein Gunnewiek
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: