为同一模型使用多个数据库

Using multiple databases for the same model

我正在开发一些需要连接到两个独立数据库的 API,包含类似的表但数据不同。

我已经在 app.phpapp_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 数据库的数据被打印了两次。

但是:

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

我做错了什么?

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

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

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

基本示例:

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();

如您所见,这不仅需要再次加载 model/table,还需要取消设置 属性 上的实例,否则 loadModel() 将不会实际加载 table,而是 return 已经在 $this->Users 属性.

上设置的实例

我建议你切换到通过 table 定位器获取你的模型,即使在你的控制器中,这样你就可以跳过这个尴尬的未设置的东西,并且你可以减少意外访问存储的旧实例的风险在 $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();

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