首页 > 解决方案 > 对同一模型使用多个数据库

问题描述

我正在研究一些需要连接到两个独立数据库的 API,其中包含相似的表但不同的数据。

我已经在我的app.phpand中配置了两个数据源app_local.php,它们都是可以访问的。

通过一些研究,我发现这ConnectionManager::alias应该是我需要的,所以我想出了这个:

// Fetching `energy` DB data
ConnectionManager::alias('energy', 'default');
$energy = $this->Users->find()->first();
debug($energy);
ConnectionManager::dropAlias('default');

// Fetching `default` (gas) DB data
$gas = $this->Users->find()->first();
debug($gas);

问题是,如果我像这样运行这些查询,调试会给出相同的数据,这意味着来自energy数据库的数据会被打印两次。

但:

看起来实际上只使用了第一个数据源。

我做错了什么?

标签: cakephpcakephp-4.x

解决方案


一旦一个表类被实例化,它将保存在实例化时分配给它的连接实例(connection选项\Cake\ORM\Table::__construct()),分别是当表第一次尝试获取连接时创建的连接实例(\Cake\ORM\Table::getConnection())。

所以单独删除别名不会做任何事情,对表的下一次调用将使用表已经拥有的连接实例,它不会尝试自己再次获取连接。

由于您希望连接更改影响所有内容,因此您必须在删除连接别名后清除表注册表,并再次加载表,以便使用实际default连接再次创建它们(如果您只想影响特定的例如,您可以通过setConnection()) 分配一个新的连接实例。为避免在创建别名时遇到与已创建的表实例相同的问题,您很可能还应该在此之后清除注册表

基本示例:

ConnectionManager::alias('energy', 'default');
$this->getTableLocator()->clear();
// table instances created after this point will respect the alias

$this->Users = null;
$this->loadModel('Users');
$energy = $this->Users->find()->first();

ConnectionManager::dropAlias('default');
$this->getTableLocator()->clear();
// table instances created after this point will use the non-aliased connection

$this->Users = null;
$this->loadModel('Users');
$gas = $this->Users->find()->first();

如您所见,这不仅需要再次加载模型/表,还需要取消设置属性上的实例,否则loadModel()实际上不会再次加载表,而是返回已在$this->Users属性上设置的实例。

我建议您切换到通过表定位器获取模型,即使在您的控制器中,这样您就可以跳过这个尴尬的未设置内容,并且您可以降低意外访问存储在属性上的旧实例的风险,例如$this->Users

ConnectionManager::alias('energy', 'default');
$this->getTableLocator()->clear();

$energy = $this->getTableLocator()-get('Users')->find()->first();

ConnectionManager::dropAlias('default');
$this->getTableLocator()->clear();

$gas = $this->getTableLocator()-get('Users')->find()->first();

您可能还应该考虑将此连接切换集中在服务中的某个位置。


推荐阅读