我在database.php中有以下配置:
'connections' => array(
'sqlite' => array(
'driver' => 'sqlite',
'database' => __DIR__.'/../database/production.sqlite',
'prefix' => '',
),
'mysql-primary' => array(
'driver' => 'mysql',
'host' => 'host1',
'port' => '3306',
'database' => 'test',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
'mysql-slave' => array(
'driver' => 'mysql',
'host' => 'host2',
'port' => '3306',
'database' => 'test',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
'default' => 'mysql-primary',
)
我想要实现的是在不可用的情况下从主DB切换到从DB。让我们说用户尝试登录:
$user = User::where('username', '=', $username)->first();
我想在这里,如果有PDOException(在不可用的情况下应该被抛出)来切换默认数据库并重试该操作。我知道它在用户模型中是可能的,但我想切换所有模型。
我尝试过但没有成功:
App::error(function(PDOException $exception)
{
Log::error("Error connecting to database: ".$exception->getMessage());
DB::setDefaultConnection('mysql-slave');
});
在filters.php中
'default' => getDatabase()
function getDatabase()
{
try{
DB::connection('mysql-master')->getDatabaseName();
}catch(PDOException $e){
return 'mysql-slave';
}
return 'mysql-master';
}
在database.php中
两者都不起作用。在Laravel 4中有没有办法解决这种问题?
答案 0 :(得分:2)
简短的回答是:你不能使用外墙(DB :: etc)来做到这一点。
为什么呢? Facade使用内部单例实例,该实例在首次访问外观时初始化。如果深入研究Laravel代码,您会发现,在服务提供程序的引导程序/寄存器功能(包括数据库服务提供程序)中,有一个内部数据库对象被创建为单例。该对象属于Illuminate \ Database \ Connectors \ ConnectionFactory类,并具有预初始化的内部PDO对象,该对象是根据存储在配置变量中的配置创建的。
更长的答案是,您可以使用类似于数据库服务提供程序中的引导代码的代码创建一个或多个您自己的类Illuminate \ Database \ Connectors \ ConnectionFactory对象。我建议您仔细阅读该引导代码并熟悉它,并且可以在此处找到代码及其文档:https://laravel.com/api/4.2/Illuminate/Database/DatabaseServiceProvider.html
可能还有另一种解决方法,包括为ConnectionFactory提供类型为Illuminate \ Database \ Connection(所有这些都可以在配置中设置)的额外连接器。这将涉及扩展现有的ConnectionFactory类,并更改数据库服务提供程序以使用您自己的扩展而不是Laravel本机类。然后你可以让ConnectionFactory提供一个内置故障转移的连接。它相当复杂但可能 - 我已经为ViewFactory类完成了但从未用于ConnectionFactory类。
对不起,这不是一个简单的HOWTO来回答你的问题,但它让你知道为什么这不能简单地用你给出的例子。使用MySQL代理或负载平衡服务可能更简单,例如,自动检测哪个服务器正在运行并向其发送请求。