I am working with a CakePHP based API that utilizes AWS Aurora to manage our MySQL database. The CakePHP application has many large read queries that that requires a separate Reader Endpoint to not exhaust the database resources.
The way this works is that AWS gives you separate endpoints to use in the host field when you connect CakePHP to it.
I went ahead and configured it the following way, which works. The folowing datasources are set up in config/app.php, using the reader and cluster (default) endpoints for the host value:
<?php
// Other data-source and app settings are omitted, to keep things simple
return [
'Datasources' => [
'default' => [
'host' => 'mydbcluster.cluster-123456789012.us-east-1.rds.amazonaws.com',
],
'read' => [
'host' => 'mydbcluster.cluster-ro-123456789012.us-east-1.rds.amazonaws.com',
],
]
];
Both the 'read' and 'default' data sources point to the same database, but so this additional data source is purely configured to support the read only host value.
At this point, all I have to do is overwrite the default connection to read on the queries that need the read connection:
<?php
/**
* Class TaskNotesController
*
* @property \App\Model\Table\TaskNotesTable $TaskNotes
*/
class TaskNotesController extends \Cake\Controller\Controller
{
public function index(): void
{
$taskNotes = $this->TaskNotes
->setConnection(\Cake\Datasource\ConnectionManager::get('read'))
->find('all')
->where(['foo' => 'bar']);
}
}
However, I would like to apply the read endpoint to all read queries in the application. It seems like Cake would have a cleaner way of doing this, to avoid attaching the setConnection() call on every query.
Can you tell me if there is a more streamlined way of doing this in CakePHP?
Thanks in advance!
2条答案
按热度按时间ou6hu8tu1#
这个主题每隔一段时间就会出现,但结论始终是,这不是核心想要支持的东西:******
所以你只能靠自己了,有很多方法可以用更DRY的方式解决这个问题,但这在很大程度上取决于你的应用程序的具体需求。很难给予任何合适的通用建议,因为做错事情会带来可怕的后果。
就像如果您盲目地将特定连接应用于所有读操作,那么当您的应用程序在不同的连接上发出读操作时,您很可能会非常伤心,而您正在执行一个基于读数据写入内容的事务。
所有这一切都是可悲的,你可以把你的模型分成读/写的,沿着CQRS的路线,你可以使用为你的表提供更直接和可重用的API的行为,你可以把你的操作移到模型层,并隐藏可能有点脏的实现,你可以根据请求的端点配置默认连接,例如,它是读还是写,等等。
有很多方法可以“解决”这个问题,但恐怕在座的任何人都无法给出明确的答案。
oxcyiej72#
我也需要这样做,并通过将Table类扩展为“AppTable”来解决这个问题。我重写了
find()
方法以使用query()
的另一个版本,我将其命名为readQuery()
。在readQuery()
中,我修改了$_connection
成员变量,使其在使用$this->query()
生成查询 * 之前 * 使用我的只读连接。然后,当生成查询时,我将其切换回写连接,并进行了检查,以确保在存在活动事务或在请求生命周期中之前已写入任何内容时没有执行此操作(因为复制可能尚未完成,并且我将获得旧数据)。这并不是很难设置;您只需要在find()中生成Query对象时对Cake的基类Table进行一点扩展以便在两个连接之间切换。