【问题标题】:Where to initialize Doctrine's default transaction isolation level in Symfony?Symfony 在哪里初始化 Doctrine 的默认事务隔离级别?
【发布时间】:2020-01-28 11:55:32
【问题描述】:

我想在我的 Symfony 应用程序中设置默认事务隔离级别 READ COMMITTED,而不是 MySQL 的默认 REPEATABLE READ

基本上,我需要确保在注入此类时在Doctrine\DBAL\Connection 上调用以下方法:

$connection->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED);

在 Symfony 应用程序中执行此操作的正确位置是什么?我虽然关于Kernel,但不确定如何在不必无条件实例化Connection 的情况下做到这一点。

相反,这应该只在 if 并且 Connection 被依赖注入容器实例化时调用。

【问题讨论】:

    标签: php symfony doctrine-orm symfony4


    【解决方案1】:

    我认为没有可用于控制捆绑级别事务隔离的配置选项。

    但可以装饰Doctrine\Bundle\DoctrineBundle\ConnectionFactory,并在createConnection() 上设置事务隔离级别,然后返回创建的连接。

    # services.yaml
        App\YourOwnConnectionFactory:
            decorates: '@doctrine.dbal.connection_factory'
    
    class YourOwnConnectionFactory
    {
        private ConnectionFactory $decorated;
    
        public function __construct(ConnectionFactory $decorated) {
            $this->decorated = $decorated;
        }
    
        public function createConnection(array $params, Configuration $config = null, EventManager $eventManager = null, array $mappingTypes = []) {
            $connection = $this->decorated->createConnection($params, $config, $eventManager, $mappingTypes);
            $connection->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED);
            return $connection;
        }
    }
    

    您还可以更改doctrine.dbal.connection 的定义以在编译器传递中添加对setTransactionIsolation() 的调用。不确定它会更好。我想这两种方法都有自己的缺点,您需要根据自己的情况进行评估:

    class FooPass implements CompilerPassInterface
    {
        public function process(ContainerBuilder $container)
        {
                $container
                    ->getDefinition('doctrine.dbal.default_connection')
                    ->addMethodCall(
                        'setTransactionIsolation',
                        [TransactionIsolationLevel::READ_COMMITTED]
                    );
    
        }
    }
    

    另一种选择是使用向编译器传递添加配置器函数:

    class FooPass implements CompilerPassInterface
    {
        public function process(ContainerBuilder $container)
        {
            $container
                ->getDefinition('doctrine.dbal.default_connection')
                ->setConfigurator([self::class, 'setTransactionIsolationLevel']);
        }
    
        public static function setTransactionIsolationLevel(Connection $connection) : void
        {
            $connection->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED);
        }
    }
    

    【讨论】:

    • 这行得通,谢谢。不过,我有点不愿意装饰一个没有实现接口的类;它对上游变化更加脆弱。我的意思是,在下一个主要版本之前肯定不会有破坏性的 API 更改,但是静态分析将无法理解它会发生的问题。难道没有办法在通过依赖注入创建Connection 之后,在它返回给调用者之前就拦截它吗?不能将Container 配置为执行此操作吗?
    • 好吧,我想您可以更改默认连接服务的定义以添加所需的方法调用。不确定它是否更好,但也许你会发现它更符合你的口味。见编辑。
    • 嗯,我也不是很喜欢,确实。我更期待可以接受回调函数来配置新构建的对象的东西,例如:->addCallback(function(Connection $connection) { $connection->setTransactionIsolation(...); });,但在 Symfony DI 中可能没有这样的东西。
    • 上述基本相同。 addMethodCall 向新配置的服务添加方法调用。答案解决了问题陈述,但如果有其他限制条件,则应在问题中提及。它开始看起来像您正在寻找的东西,它更像是一种专门的服务定义,尽管我不确定我是否完全理解与上述不同的应用方式。很遗憾您没有发现它有用或有帮助。
    • 我冒昧地使用配置器选项更新您的答案。我想我们现在已经调查了所有可能的选择。感谢您的宝贵时间!
    猜你喜欢
    • 1970-01-01
    • 2020-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-08
    • 1970-01-01
    • 2012-08-01
    相关资源
    最近更新 更多