2016-11-14 2 views
0

Ich versuche Pessimistic Locking mit Doctrine ORM für PostgreSql zu verwenden. Doctrine und PostgreSql mit Standardkonfigurationen (ohne Änderungen).Doktrin (postgresql) Pessimistische Sperre - wirft keine PessimisticLockException

Dies ist ein Codebeispiel (Symfony-Befehl).

$sleep - das ist die Zeit in Sekunden

$manager = $this->getContainer()->get('mmi.manager.message'); 
$conn = $manager->em()->getConnection(); 

$manager->em()->getConnection()->beginTransaction(); 
try { 
    $entity = $manager->repo()->find('cd7eb9e9', LockMode::PESSIMISTIC_WRITE); 

    $entity->setState(EntityActionInterface::STATE_IN_PROGRESS); 
    $manager->em()->persist($entity); 
    $manager->em()->flush(); 

    $ts = (new \DateTime())->getTimestamp(); 
    $output->writeln("TS: {$ts}"); 

    if ($sleep) { 
     $output->writeln("Sleep: {$sleep}"); 
     sleep($sleep); 
    } 

    $entity->setMessage([$ts]); 
    $manager->em()->persist($entity); 
    $manager->em()->flush(); 

    $conn->commit(); 
} catch (PessimisticLockException $ex) { 
    var_dump(get_class($ex)); 

    $conn->rollBack(); 
    throw $ex; 
} catch (\Exception $ex) { 
    var_dump(get_class($ex)); 

    $conn->rollBack(); 
    throw $ex; 
} 

Wie getestet

Run zwei Befehle. Der erste Befehl wird mit einem Timeout von 20 Sekunden ausgeführt. Der zweite Befehl wird ohne Zeitüberschreitung ausgeführt.

Erwartetes Ergebnis

Zweiter Befehl wirft PessimisticLockException

Tatsächliches Ergebnis

Zweiten Befehl wartet auf erst Transaktionscommit und aktualisiert Reihe.

Frage

Was soll ich tun, um Lehre PessimisticLockException zu machen werfen, wenn Zeile jetzt gesperrt ist?

Antwort

0

Fo zuerst: Wie

PESSIMISTIC_WRITE PESSIMISTIC_WRITE für PostgreSql Plattform arbeiten - das ist Abfrage SELECT ... FOR UPDATE. Diese Abfrage sperrt die ausgewählte Zeile und andere Verbindungen, die dieselbe Zeile angefordert haben, und warten auf die aktuelle Verbindung, um ihre Arbeit zu beenden.

In meinem Fall starte ich zwei Prozesse und zweite wartet auf den ersten. Und das ist richtiges Verhalten.

Mein Fehler: Ich bin Doctrine Quellcode erkunden und finden PessimisticLockException Klasse. Also entscheide ich, dass Doctrine diese Ausnahme bei pessimistischer Sperre auswirft. Aber diese Klasse wird nirgends in Doctrine verwendet.

Also, wie ich dieses Problem gelöst.

Meine aktuelle Implementierung erforderte jetzt das Verhalten für gesperrte Zeilen. Und PostgreSql 9.5 hat diese Funktion - SKIP LOCKED. Aber Doctrine hat keine Implementierung für diese Funktion.

Was können wir tun?

Wir können Lehre postgresql platfrom Klasse überschreiben.

use Doctrine\DBAL\Platforms\PostgreSqlPlatform; 

class PgSqlPlatform extends PostgreSqlPlatform 
{ 
    /** 
    * Returns the FOR UPDATE expression. 
    * 
    * @return string 
    */ 
    public function getForUpdateSQL() 
    { 
     return 'FOR UPDATE SKIP LOCKED'; 
    } 
} 

definieren es als Dienst ist

#app/config/services.yml 
services: 
    mmi.dbal.pgsql_platform: 
     class: {Namespace}\PgSqlPlatform 

Und gesetzt tot Lehre Config

#app/config/config.yml 
doctrine: 
    dbal: 
     connections: 
      mmi: 
       driver: pdo_pgsql 
       host:  ... 
       ... 
       platform_service: 'mmi.dbal.pgsql_platform' 

Das ist alles. Jetzt können wir die pessimistische Sperre verwenden, ohne zu warten.

Verwandte Themen