Я использую Symfony 4 для взаимодействия с существующей настройкой Master/Slave MySQL и выполняю запросы к серверу с использованием raw sql. Исходный SQL - единственный вариант на данный момент.
Я использую полный список процессов; на сервере БД, чтобы контролировать, какая БД используется, и я вижу только соединения с главным сервером. Не кажется, что любой из рабов когда-либо используется.
Для справки, у меня есть две настройки dbal connections, по умолчанию это НЕ master/slave, и используется сопоставление 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
Я настроил своих менеджеров объектов в моих службах.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);
Пожалуйста, дайте мне знать, если мне не хватает какой-либо полезной конфигурации.
Большое спасибо за помощь.
Спасибо @Cerad за подсказку, что привело меня в правильном направлении. Поскольку я больше не пытался использовать диспетчер сущностей для необработанных запросов, которые не были сопоставлены с сущностями, я мог бы работать с соединением напрямую.
я Создал класс оболочки, который расширил MasterSlaveConnection. Это работало до тех пор, пока я использовал executeQuery(). В документах, которые должны использоваться для запроса подчиненных. Однако в моем запросе использовались команды prepare() и query(), которые заставляют мастер-соединение.
Таким образом, внутри моего нового класса оболочки я создал два новых метода: prepareSlave() и querySlave(), которые делают то же самое, что и оригинал; однако они $this-> connect ('slave'); вместо $this-> connect ('master');
Теперь все мои прочитанные запросы попали в рабство, а все остальное - мастеру.
Итак, вот следующие обновления, которые я сделал для конфигурации выше, чтобы достичь этого:
doctrine.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().