2016-02-22 62 views
4

我試圖使用會話處理程序和學說DBAL之間到我的數據庫相同的連接之間的數據庫:共享連接DBAL和會話處理的Symfony2

config.yml

framework: 
    session: 
     handler_id: session.handler.one_connection_pdo 

services.yml

session.handler.one_connection_pdo: 
    class:  AppBundle\Session\OneConnectionPdoHandler 
    public: false 
    arguments: 
     - "@database_connection" 
     - [] 

的appbundle /會話/ OneConnectionPdoHandler.php

namespace AppBundle\Session; 


use Doctrine\DBAL\Connection; 
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; 

class OneConnectionPdoHandler extends PdoSessionHandler 
{ 

    public function __construct($pdoOrDsn, array $options) 
    { 
     if ($pdoOrDsn instanceof Connection) { 
      $pdoOrDsn = $pdoOrDsn->getWrappedConnection(); 
     } 
     parent::__construct($pdoOrDsn, $options); 
    } 

} 

一切似乎都瀏覽應用程序時的工作,但因爲我得到的錯誤,我不能更新任何實體:

PDOException: There is already an active transaction 
at n/a 
    in .../vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php line 1176 

at PDO->beginTransaction() 
    in .../vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php line 1176 

at Doctrine\DBAL\Connection->beginTransaction() 
    in .../vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php line 373 

at Doctrine\ORM\UnitOfWork->commit(null) 
    in .../vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php line 356 

at Doctrine\ORM\EntityManager->flush() 
    in .../src/AppBundle/Controller/Admin/DistributorsController.php line 66 

at AppBundle\Controller\Admin\DistributorsController->editAction(object(Distributor), object(Request)) 
    in line 

at call_user_func_array(array(object(DistributorsController), 'editAction'), array(object(Distributor), object(Request))) 
    in .../vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php line 139 

at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), '1') 
    in .../vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php line 62 

at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), '1', true) 
    in .../vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php line 169 

at Symfony\Component\HttpKernel\Kernel->handle(object(Request)) 
    in .../web/app_dev.php line 31 

有分享主義DBAL和自定義PDO處理器之間的連接的方法嗎?

//編輯

我終於發現裏面PdoSessionHandler類的解決方案。

默認情況下,PDO處理程序在讀取和寫入會話時使用事務。它首先開始交易read()並承諾close()。在這之間有一些數據庫操作$em->persist($entity); $em->flush(),它產生了另一個產生錯誤的事務。

裏面PdoSessionHandler類,我發現有一個lock_mode選項,可以設置這樣的:

session.handler.one_connection_pdo: 
    class:  AppBundle\Session\OneConnectionPdoHandler 
    public: false 
    arguments: 
     - "@database_connection" 
     - { lock_mode: 1 } 

當LOCK_MODE設置爲1(PdoSessionHandler::LOCK_ADVISORY)PDO處理程序將使用諮詢鎖,而不是交易,將有不再有交易錯誤。

+0

典型地,這些種類的當循環訪問一組結果並嘗試在循環中執行數據庫更新時,會發生錯誤。看起來你也有一些實體管理器正在進行,所有的都共享相同的連接對象。其他人可能會有更好的建議,但我會建議僅爲會話代碼創建連接對象:http://symfony.com/doc/current/cookbook/doctrine/multiple_entity_managers.html。這將消除意外的交互。或者可以使用fetchAll而不是查詢循環。 – Cerad

+0

我對這個處理程序進行了一些調查。它看起來是在首次讀取'PdoSessionHandler :: read() - > doRead() - > getSelectSql() - > beginTransaction()'並且直到close()'結束事務時纔開始事務。在教義之間嘗試更改實體:'$ em-> persist($ entity); $ em-> flush()'產生另一個事務並觸發錯誤。我想我現在會堅持使用memcached處理程序。 Thx – piotrekkr

+0

是的。我似乎從Symfony 2的早期版本中記得這一點。無論如何,我從來不希望我的會話信息存儲在生產數據庫中。因此需要會話特定的數據庫和連接。 – Cerad

回答

3

在Symfony的3(表觀\設置\ config.yml)〜

framework: 
    session: 
    handler_id: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler 

在(表觀\設置\ services.yml):

Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler: 
     arguments: 
      - !service { class: PDO, factory: 'database_connection:getWrappedConnection' } 
      - {lock_mode: 1 }