2016-11-14 6 views
0

Я пытаюсь использовать пессимистическую блокировку с доктриной ORM для PostgreSql. Doctrine и PostgreSql с настройками по умолчанию (без каких-либо изменений).Доктрина (postgresql) Пессимистическая блокировка - не бросает PessimisticLockException

Это пример кода (Symfony Command).

$sleep - это время в секундах

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

Как тестируемых

Выполнить две команды. Первая команда запускается с таймаутом 20 секунд. Вторая команда запускается без какого-либо таймаута.

Ожидаемый результат

Вторая команда бросает PessimisticLockException

Фактический результат

Second ждет команды для первой транзакции, а затем обновляет строку.

Вопрос

Что я должен сделать, чтобы бросить Доктрина PessimisticLockException если строка теперь заблокирована?

ответ

0

Fo первый: Как работает PESSIMISTIC_WRITE для платформы PostGreSQL

PESSIMISTIC_WRITE - это запрос SELECT ... FOR UPDATE. Этот запрос блокирует выбранную строку и другие коннекции, которые запрашивают одну и ту же строку, waitng для текущего завершения соединения - это работа.

В моем случае я запускаю два процесса и второй, ожидая окончания первого. И это правильное поведение.

Моя ошибка: Я изучаю исходный код Doctrine и находил PessimisticLockException класс. Итак, я решаю, что Doctrine выбрасывает это исключение при использовании пессимистической блокировки. Но этот класс не используется нигде в Доктрине.

Итак, как я решил эту проблему.

Мое текущее выполнение требует текущего поведения для заблокированных строк. А PostgreSql 9.5 имеет эту функцию - SKIP LOCKED. Но у Doctrine нет реализации для этой функции.

Что мы можем сделать?

Мы можем переопределить класс доктрины postgresql platfrom.

use Doctrine\DBAL\Platforms\PostgreSqlPlatform; 

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

Определить это как сервис

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

и установить TOT доктрины конфигурации

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

Это все. Теперь мы можем использовать пессимистический замок, не дожидаясь ожидания.

Смежные вопросы