如何覆盖Laravel的数据库连接

11 浏览
0 Comments

如何覆盖Laravel的数据库连接

大家好,

我已经花了超过10个小时试图解决这个问题,现在我决定在发疯之前寻求帮助。

我想要实现的是一种多租户的方式,即为每个客户分配一个专用数据库,并根据请求的发起者加载相应的数据库。例如,如果客户A发送请求,加载数据库A;如果客户B发送请求,加载数据库B。由于我们有成千上万个客户,所以在database.php文件中预定义所有配置不可行。

在一些特殊情况下,无论请求的发起者如何,都应该加载相同的数据库。例如,如果请求是X,总是加载数据库C。

我有以下架构:

BaseModel继承自Eloquent Model。

应用模型继承自BaseModel。

一些与应用模型交互的库。

由于我所有的数据库请求都经过BaseModel,我认为可能会起作用的最好解决方案是在BaseModel的构造函数中插入切换到正确数据库的代码。例如:

class BaseModel extends \Eloquent { 
public function __construct(array $attributes = array()) {     
    $currentConfigs = \Config::get('database.connections.customers');    
    $currentConfigs['database'] = 'db_A'; //根据请求的不同而变化
    $currentConfigs['prefix'] = 'custName'; //根据请求的不同而变化                              
    \Config::set('database.connections.customers', $currentConfigs); 
    parent::__construct($attributes);        
} 

我面临的问题是我似乎只能设置配置一次。换句话说,如果在请求的生命周期内只需要数据库A或B,一切都正常。但是,如果我需要切换到数据库C,这就不起作用了。BaseModel在A或B中继续寻找所需的表,即使我试图显式加载C。看起来数据库设置是不可变的或类似于这样的东西。

也就是说,我有几个问题:

1. 在运行时动态加载不同的数据库的最佳方法是什么,要考虑到一个请求可能需要查询多个数据库而不仅仅是一个?

2. 如何卸载或重置数据库连接,以便设置一个新的连接?

3. Laravel中的哪个方法可以给我关于当前数据库连接的信息?我需要调试的方法,但我对可能的方法一无所知。

任何帮助/提示将不胜感激。

0
0 Comments

如何覆盖Laravel的数据库连接

问题的原因是,Laravel在配置文件中建立了一个连接,并将其保存在内存中。如果要通过设置新的连接变量来实现,需要在进行更改后重新连接。(还要注意,您也可以使用强大的点表示法直接设置配置)

\Config::set('database.connections.customers.database', 'db_A');
DB::reconnect('customers');

然而,我认为更好的方法是使用SQL来切换数据库

DB::unprepared('USE db_A');

要获取当前数据库名称,也可以使用SQL

DB::select('SELECT DATABASE()')[0]->{"DATABASE()"} // 如果您不使用MySQL,DATABASE()可能是其他内容

更新 - 表前缀

使表前缀也具有动态性的一种简单方法是在您的BaseModel构造函数中添加以下内容

$this->setTable('custName'.$this->getTable());

太棒了,我认为这是缺失的95%。我真的很想接受你的答案,但似乎还有一个问题 🙁 在DB::reconnect之后,表前缀似乎被忽略了。有什么想法吗?我之前没有提到这一点,因为我认为这是无关紧要的,但我的一些表具有前缀,而其他表则没有,我需要能够在运行时设置这些前缀...

嗯...也许在重新连接后尝试DB::setDefaultConnection('customers');。 (不知道为什么,但我在一个在线论坛上找到了这个方法)。如果你使用USE db_A方法呢?

setDefaultConnection没有起作用:(我将尝试使用USE db_A方法,但我想知道它是否会保留前缀...稍后我会尝试并更新话题。

它是相同的,前缀被忽略了...目前唯一的解决方法是在进入BaseModel构造函数之前引入前缀。这不是我希望的那么干净,但除非有其他建议,否则这很可能是我最终要做的...

奇怪...我刚刚试了一下,一切都正常。您在数据库配置中定义了前缀,对吗?

不完全是。由于每个客户都有一个前缀,如果我们把所有内容都放在数据库配置中,那将是丑陋的。前缀在数据库配置中是空的,但我通过BaseModel中的代码进行了设置(出于简单起见,我没有放在这里,但将更新问题)。总结一下:我的前缀配置为空,但我通过BaseModel中的代码进行了设置(但不起作用)...

我明白了...我不知道为什么在更改数据库时会忽略它,但我在我的答案中更新了一个解决该问题的方法的解释。

我没有足够的话来感谢你:) setTable拯救了这一天!

对于任何寻找相同问题的人,我通过执行DB::purge(DB::getDefaultConnection()); DB::Reconnect($new_connection);解决了前缀问题。

0