Symfony 4 中未使用原始查询的奴隶
Slaves not used in Symfony 4 with Raw Queries
我正在使用 Symfony 4 与现有 Master/Slave MySQL 设置交互,并使用原始 sql 对服务器执行查询。 Raw SQL 是目前唯一的选择。
我正在使用 show full processlist;在数据库服务器上监视使用哪个数据库,我只看到与主服务器的连接。似乎从未使用过任何奴隶。
作为参考,我有两个 dbal 连接设置,默认为 NOT master/slave,并使用 orm 映射。第二个是我遇到问题的 master/slave,这是我正在执行原始 sql 查询的服务器。
下面是我的doctrine.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)被注入到 class 的构造函数中,然后查询按如下方式执行:
$result = $this->em->getConnection()->prepare($sql);
$result->execute($args);
如果我遗漏了任何有用的配置,请告诉我。
非常感谢您的帮助。
感谢@Cerad 的提示,它让我朝着正确的方向前进。由于我不再尝试对未映射到实体的原始查询使用实体管理器,因此我可以直接使用连接。
我创建了一个扩展 MasterSlaveConnection 的包装器 class。只要我使用 executeQuery(),它就有效。根据文档,必须使用它来查询奴隶。但是,我的查询需要使用 prepare() 和 query(),它们都强制主连接。
所以在我的新包装器中 class 我创建了两个新方法,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
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()。
我正在使用 Symfony 4 与现有 Master/Slave MySQL 设置交互,并使用原始 sql 对服务器执行查询。 Raw SQL 是目前唯一的选择。
我正在使用 show full processlist;在数据库服务器上监视使用哪个数据库,我只看到与主服务器的连接。似乎从未使用过任何奴隶。
作为参考,我有两个 dbal 连接设置,默认为 NOT master/slave,并使用 orm 映射。第二个是我遇到问题的 master/slave,这是我正在执行原始 sql 查询的服务器。
下面是我的doctrine.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)被注入到 class 的构造函数中,然后查询按如下方式执行:
$result = $this->em->getConnection()->prepare($sql);
$result->execute($args);
如果我遗漏了任何有用的配置,请告诉我。
非常感谢您的帮助。
感谢@Cerad 的提示,它让我朝着正确的方向前进。由于我不再尝试对未映射到实体的原始查询使用实体管理器,因此我可以直接使用连接。
我创建了一个扩展 MasterSlaveConnection 的包装器 class。只要我使用 executeQuery(),它就有效。根据文档,必须使用它来查询奴隶。但是,我的查询需要使用 prepare() 和 query(),它们都强制主连接。
所以在我的新包装器中 class 我创建了两个新方法,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
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()。