Подчиненные устройства, не используемые в Symfony 4 с необработанными запросами

Я использую Symfony 4 для взаимодействия с существующей установкой Master/Slave MySQL и выполняю запросы к серверу, используя необработанный sql. Необработанный SQL — единственный вариант на данный момент.

я использую показать полный список процессов; на сервере БД, чтобы контролировать, какая БД используется, и я вижу только подключения к главному серверу. Не похоже, чтобы какие-либо из рабов когда-либо использовались.

Для справки, у меня установлено два соединения dbal, по умолчанию НЕ главный/подчиненный, и используется сопоставление orm. Второй — это ведущий/ведомый, с которым у меня проблемы, и это сервер, к которому я выполняю необработанные запросы sql.

Ниже моя доктрина.yml:

doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                driver:   pdo_mysql
                host:     "%env(DATABASE_HOST)%"
                dbname:   "db1"
                user:     "%env(DATABASE_USER)%"
                password: "%env(DATABASE_PASS)%"
                charset:  UTF8
            ds:
                driver:   pdo_mysql
                host:     "%env(DS_DATABASE_HOST)%"
                dbname:   "db2"
                user:     "%env(DS_DATABASE_USER)%"
                password: "%env(DS_DATABASE_PASS)%"
                slaves:
                    slave1:
                        host:     "%env(DS_DATABASE_SLAVE1_HOST)%"
                        user:     "%env(DS_DATABASE_USER)%"
                        password: "%env(DS_DATABASE_PASS)%"
                        dbname:   "db2"
                    slave2:
                        host:     "%env(DS_DATABASE_SLAVE2_HOST)%"
                        user:     "%env(DS_DATABASE_USER)%"
                        password: "%env(DS_DATABASE_PASS)%"
                        dbname:   "db2"

orm:
    default_entity_manager: default
    entity_managers:
        default:
            connection: default
            mappings:
                Main:
                    is_bundle: false
                    type: annotation
                    dir: '%kernel.project_dir%/src/Entity/Main'
                    prefix: 'App\Entity\Main'
                    alias: Main
        ds:
            connection: ds

Я настроил свои менеджеры сущностей в файле services.yml следующим образом:

# Entity managers
App\Service\Database\MainEntityManager:
    arguments:
        $wrapped: '@doctrine.orm.default_entity_manager'
App\Service\Database\DSEntityManager:
    arguments:
        $wrapped: '@doctrine.orm.ds_entity_manager'

Менеджер сущностей (в данном случае DSEntityManager) внедряется в конструктор класса, после чего запрос выполняется как таковой:

    $result = $this->em->getConnection()->prepare($sql);
    $result->execute($args);

Пожалуйста, дайте мне знать, если мне не хватает какой-либо полезной конфигурации.

Большое спасибо за помощь.


person Dbl0McJim    schedule 20.06.2018    source источник
comment
Нет необходимости в диспетчере сущностей ds, вы можете напрямую внедрить объект подключения и использовать его. На самом деле существует атрибут wrapper_class, поэтому вы можете указать против него. Никогда не использовал материал master/slave, поэтому сомнительно, что прямое внедрение соединения действительно поможет.   -  person Cerad    schedule 20.06.2018


Ответы (1)


Спасибо @Cerad за подсказку, которая привела меня в правильном направлении. Поскольку я больше не пытался использовать диспетчер сущностей для необработанных запросов, которые не были сопоставлены с сущностями, я мог работать с соединением напрямую.

Я создал класс-оболочку, который расширил MasterSlaveConnection. Это работало, пока я использовал executeQuery(). Согласно документам, это должно использоваться для запроса ведомых устройств. Однако мой запрос требовал использования prepare() и query(), которые инициируют основное соединение.

Итак, внутри моего нового класса-оболочки я создал два новых метода, prepareSlave() и querySlave(), которые делают то же самое, что и оригинал; однако они делают $this->connect('slave'); вместо $this->connect('master');

Теперь все мои запросы на чтение попадают в ведомое устройство, а все остальное — в ведущее.

Итак, вот следующие обновления, которые я сделал в приведенной выше конфигурации, чтобы добиться этого:

доктрина.yml

        ds:
            driver:   pdo_mysql
            host:     "%env(DS_DATABASE_HOST)%"
            dbname:   "db2"
            user:     "%env(DS_DATABASE_USER)%"
            password: "%env(DS_DATABASE_PASS)%"
            wrapper_class: "%env(DS_DATABASE_PASS)%"
            slaves: App\Service\Database\DSWrapper
                slave1: ...

services.yml

# DBAL connections
App\Service\Database\DSWrapper: '@doctrine.dbal.ds_connection'

Мой новый класс-оболочка

class DSWrapper extends MasterSlaveConnection
{
public function prepareSlave($statement)
{
    $this->connect('slave');

    try {
        $stmt = new Statement($statement, $this);
    } catch (\Exception $ex) {
        throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $statement);
    }

    $stmt->setFetchMode($this->defaultFetchMode);

    return $stmt;
}

public function querySlave()
{
    $this->connect('slave');

    $args = func_get_args();

    $logger = $this->getConfiguration()->getSQLLogger();
    if ($logger) {
        $logger->startQuery($args[0]);
    }

    $statement = $this->_conn->query(...$args);

    if ($logger) {
        $logger->stopQuery();
    }

    return $statement;
}
}

Так что теперь, если мне нужно выполнить запрос, который обычно требует использования prepare() и query(), вместо этого я использую prepareSlave() и querySlave().

person Dbl0McJim    schedule 24.06.2018