Symfony 4、Doctrine 和 AWS RDS 只读副本的使用
Symfony 4, Doctrine and AWS RDS read replica usage
我即将开始将 RDS 与主 read/write 和从属只读设置一起使用。
我读过 Doctrine MasterSlaveConnection 类型。
但是,我会创建一些端点,我想使用只读副本(我的大部分 GET 端点),有些端点需要写入数据(PUT、PATCH、DELETE 端点)。
我也在使用 API 平台。
在 Symfony 4 和 Doctrine 2 中实现这一目标的最佳方法是什么?
我过去所做的只是使用不同的连接。
类似于:
doctrine:
dbal:
default_connection: default
connections:
default:
# This is your Master
url: '%env(DATABASE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
slave:
# This would be the slave
url: '%env(DATABASE_SLAVE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: Main
slave:
connection: slave
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: Main
https://symfony.com/doc/current/doctrine/multiple_entity_managers.html
然后在您的控制器或业务逻辑中,您可以选择使用默认实体管理器:
// Controller
$this->getDoctrine()->getEntityManager();
或者你可以获取slave连接:
// Controller
$this->getDoctrine()->getEntityManager('slave');
如果您需要它只对所有请求起作用,而不必为所有内容创建特殊操作,那么您最好的选择是装饰 Collection 和 Item DataProviders 以实现学说。
https://symfony.com/doc/current/service_container/service_decoration.html
https://github.com/api-platform/core/blob/master/src/Bridge/Doctrine/Orm/CollectionDataProvider.php
https://github.com/api-platform/core/blob/master/src/Bridge/Doctrine/Orm/ItemDataProvider.php
所以基本上你需要根据 $opperationName
更改选择的经理,例如:
if($opperationName === 'GET'){
$manager = $this->managerRegistry->getManager('slave');
} else {
$manager = $this->managerRegistry->getManager();
}
感谢@Chase 提供的解决方案。你成就了我的一天。尽管它在 'dev' 环境中对我有用,但在切换到 'prod' 时我遇到了问题。我收到无法找到实体的错误。解决方案来自 this post - 感谢@xabbuh。基本上我必须将 default_entity_manager: name_of_default_em
添加到 doctrine.yml。这是代码的副本:
# config/packages/prod/doctrine.yaml
doctrine:
orm:
default_entity_manager: BOE <- add this line to let know prod about default em
auto_generate_proxy_classes: false
metadata_cache_driver:
type: service
id: doctrine.system_cache_provider
query_cache_driver:
type: service
id: doctrine.system_cache_provider
result_cache_driver:
type: service
id: doctrine.result_cache_provider
# ...
您实际上不需要设置多个实体管理器,也不是更可取的,因为处理一个具有多个实体管理器的实体很困难。
使用 Doctrine 2.2,您可以直接从配置中设置 slaves/replicas,无需额外的实体管理器:
示例:
doctrine:
dbal:
default_connection: default
connections:
default:
dbname: '%env(DATABASE_DBNAME)%'
user: '%env(DATABASE_USER)%'
password: '%env(DATABASE_PASSWORD)%'
host: '%env(DATABASE_HOST)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
slaves:
ro_replica:
dbname: '%env(REPLICA_DBNAME)%'
user: '%env(REPLICA_USER)%'
password: '%env(REPLICA_PASSWORD)%'
host: '%env(REPLICA_HOST)%'
charset: utf8mb4
我即将开始将 RDS 与主 read/write 和从属只读设置一起使用。
我读过 Doctrine MasterSlaveConnection 类型。
但是,我会创建一些端点,我想使用只读副本(我的大部分 GET 端点),有些端点需要写入数据(PUT、PATCH、DELETE 端点)。
我也在使用 API 平台。
在 Symfony 4 和 Doctrine 2 中实现这一目标的最佳方法是什么?
我过去所做的只是使用不同的连接。
类似于:
doctrine:
dbal:
default_connection: default
connections:
default:
# This is your Master
url: '%env(DATABASE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
slave:
# This would be the slave
url: '%env(DATABASE_SLAVE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: Main
slave:
connection: slave
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: Main
https://symfony.com/doc/current/doctrine/multiple_entity_managers.html
然后在您的控制器或业务逻辑中,您可以选择使用默认实体管理器:
// Controller
$this->getDoctrine()->getEntityManager();
或者你可以获取slave连接:
// Controller
$this->getDoctrine()->getEntityManager('slave');
如果您需要它只对所有请求起作用,而不必为所有内容创建特殊操作,那么您最好的选择是装饰 Collection 和 Item DataProviders 以实现学说。
https://symfony.com/doc/current/service_container/service_decoration.html
https://github.com/api-platform/core/blob/master/src/Bridge/Doctrine/Orm/CollectionDataProvider.php
https://github.com/api-platform/core/blob/master/src/Bridge/Doctrine/Orm/ItemDataProvider.php
所以基本上你需要根据 $opperationName
更改选择的经理,例如:
if($opperationName === 'GET'){
$manager = $this->managerRegistry->getManager('slave');
} else {
$manager = $this->managerRegistry->getManager();
}
感谢@Chase 提供的解决方案。你成就了我的一天。尽管它在 'dev' 环境中对我有用,但在切换到 'prod' 时我遇到了问题。我收到无法找到实体的错误。解决方案来自 this post - 感谢@xabbuh。基本上我必须将 default_entity_manager: name_of_default_em
添加到 doctrine.yml。这是代码的副本:
# config/packages/prod/doctrine.yaml
doctrine:
orm:
default_entity_manager: BOE <- add this line to let know prod about default em
auto_generate_proxy_classes: false
metadata_cache_driver:
type: service
id: doctrine.system_cache_provider
query_cache_driver:
type: service
id: doctrine.system_cache_provider
result_cache_driver:
type: service
id: doctrine.result_cache_provider
# ...
您实际上不需要设置多个实体管理器,也不是更可取的,因为处理一个具有多个实体管理器的实体很困难。
使用 Doctrine 2.2,您可以直接从配置中设置 slaves/replicas,无需额外的实体管理器:
示例:
doctrine:
dbal:
default_connection: default
connections:
default:
dbname: '%env(DATABASE_DBNAME)%'
user: '%env(DATABASE_USER)%'
password: '%env(DATABASE_PASSWORD)%'
host: '%env(DATABASE_HOST)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
slaves:
ro_replica:
dbname: '%env(REPLICA_DBNAME)%'
user: '%env(REPLICA_USER)%'
password: '%env(REPLICA_PASSWORD)%'
host: '%env(REPLICA_HOST)%'
charset: utf8mb4