2016-11-14 40 views
0

我嘗試使用悲觀鎖定與Doctrine ORM for PostgreSql。 Doctrine和PostgreSql默認配置(沒有任何改變)。學說(postgresql)悲觀鎖定 - 不拋出PessimisticLockException

這是代碼示例(Symfony命令)。

$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

實際結果的第一交易

第二個命令等待提交,然後更新行。

問題

我應該怎麼做才能讓學說扔PessimisticLockException如果行已被鎖定?

回答

0

佛第一:如何PostgreSQL的平臺上工作PESSIMISTIC_WRITE

PESSIMISTIC_WRITE - 這是查詢SELECT ... FOR UPDATE。此查詢鎖定選定的行和其他連接請求同一行,等待當前連接完成它的工作。

在我的情況下,我開始兩個進程,第二個等待完成第一個。這是正確的行爲。

我的錯誤:我在探索Doctrine源代碼和找到PessimisticLockException類。所以,我決定當使用悲觀鎖時,Doctrine拋出這個異常。但是這個階級在教義的任何地方都沒有用過。

那麼,我是如何解決這個問題的。

我當前的實現需要nowait鎖定行的行爲。而PostgreSql 9.5有這個功能 - SKIP LOCKED。但是Doctrine沒有實現這個功能。

我們能做什麼?

我們可以重寫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' 

這就是全部。現在我們可以不用等待而使用悲觀鎖。