使用 Laravel Eloquent 连接同一服务器上不同数据库中的两个 MySQL 表

Posted

技术标签:

【中文标题】使用 Laravel Eloquent 连接同一服务器上不同数据库中的两个 MySQL 表【英文标题】:Join two MySQL tables in different databases on the same server with Laravel Eloquent 【发布时间】:2017-05-16 08:53:03 【问题描述】:

我在两个不同的数据库中有两个表。两个数据库都托管在同一个 AWS RDS 服务器上。我有一个可以访问两个数据库的用户帐户。 我在 config\database.php 中定义了两个不同的连接:

return array(
    'default' => 'mysql',
    'connections' => array(
        # Our primary database connection
        'mysql' => array(
            'driver'    => 'mysql',
            'host'      => 'samehost',
            'database'  => 'database1',
            'username'  => 'user1',
            'password'  => 'pass1'
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
        ),
        # Our secondary database connection
        'mysql2' => array(
            'driver'    => 'mysql',
            'host'      => 'samehost',
            'database'  => 'database2',
            'username'  => 'user2',
            'password'  => 'pass2'
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
        ),
    ),
);

我有两个模型用于table1database1 的连接和table2database2 的连接。两个表都有一个列id。如何使用 Eloquent 模型对具有相同 id 的行进行查询?

【问题讨论】:

只要使用 databaseName.tableName 就可以了 fideloper.com/laravel-multiple-database-connections @FazalRasel 谢谢,但它没有谈论如何加入表格。 如果您已经使用不同的数据库定义了模型,例如`protected $connection = 'mysql2';`,那么只需定义模型之间的正常关系。 @FazalRasel 没用。即使我在两个模型中定义了一个关系,它也显示调用未定义的方法 Illuminate\Database\Query\Builder::table2 错误。如果我使用 ->with('table2') 则不会收到错误,但表 2 的结果为 null 【参考方案1】:

这个解决方案对我有用:

Model1::where('postID',$postID)
      ->join('database2.table2 as db2','Model1.id','=','db2.id')
      ->select(['Model1.*','db2.firstName','db2.lastName'])
      ->orderBy('score','desc')
      ->get();

【讨论】:

有没有办法在表名的配置中使用$connection?不同环境中的数据库名称可能不同 我们不应该将数据库名称添加为硬代码。如果有人从 env 文件中更改数据库名称怎么办 换个服务器怎么样?【参考方案2】:

如果你有两个数据库在同一个连接上并且设置为默认,你可以尝试这种方式。

$query = DB::table('database1.table1 as dt1')->leftjoin('database2.table2 as dt2', 'dt2.ID', '=', 'dt1.ID');        
$output = $query->select(['dt1.*','dt2.*'])->get();

我已经在我的本地主机上尝试过它的工作。

【讨论】:

谢谢,但您使用了查询生成器。我问如何用 Eloquent 模型做到这一点。 我可以从您的答案中对 eloquent 模型进行连接查询,但有一些细微的变化。谢谢【参考方案3】:

到目前为止,有些答案是正确的,我只是添加这个以防有人正在寻找完整的动态解决方案(只需确保您的数据库都在同一台服务器中并且您的帐户可以访问它们)(对于这个答案,我假设您已经设置了你的配置文件和模型文件)

$databaseName1 = (new Model1())->getConnection()->getDatabaseName();
$tableName1 = (new Model1())->getTable();
$tableName2 = (new Model2())->getTable();

然后你可以使用 Laravel 提供的任何你想要的连接方法,我看到很多人犯的另一个错误是他们坚持使用 DB 门面来启动查询,事实并非如此

$databaseName2 = (new Model2())->getConnection()->getDatabaseName();
DB::join($databaseName1 . '.' . $tableName1, function($join) use ($databaseName1, $tableName1, $databaseName2, $tableName2) 
    $join->on($databaseName1 . '.' . $tableName1 . '.id', $databaseName2 . '.' . $tableName2 . '.table_id');
)->...

同样适用

Model2::join($databaseName1 . '.' . $tableName1, function($join) use ($databaseName1, $tableName1, $tableName2) 
    $join->on($databaseName1 . '.' . $tableName1 . '.id', $tableName2 . '.table_id');
)->...

对于第二种方法,您不需要第二个连接,因为 Laravel 将根据您的模型的连接默认选择连接,所有其他相关子句中的数据也是如此(例如 where()、groupBy())。我通常根据它们的模型名称来命名变量。

【讨论】:

这是我正在寻找的,但不幸的是我遇到了一个错误。我的配置文件已正确定义。当通过->with() 中的关系调用时,来自另一个数据库的表模型正在工作,但是当使用->join() 时,它会抛出错误SQLSTATE[42P01]: Undefined table: 7 ERROR: relation xxxx does not exist 我没有你的代码,我猜这个错误是由于使用了错误的模型造成的,当你同时使用 join 和 with 子句时,你使用的第一个模型是基础,所以无论你使用什么 join,即使你的数据集发生了变化,基础模型中定义的基础模型和它的关系仍然是同一个集合,当你加入A和B时,你只能使用A的关系。 这真的很有帮助,因为我有 2 个连接,而第二个连接的数据库名称是动态的。非常感谢!【参考方案4】:

这很棘手,但可以实现。但是有一些限制,无论如何可能会导致原始解决方案。

这是你需要的,假设 db1 是默认的:

// class ModelOne
public function modelTwo()

return $this->hasOne('ModelTwo', 'id');


//class ModelTwo
protected $table = 'db2.model_two_table';

public function modelOne()

return $this->belongsTo('ModelOne', 'id');

// then
$model1 = ModelOne::with('modelTwo')->get();
$model1 = ModelOne::has('modelTwo')->first(); 
// and so on

请注意,您不能在 db 配置中为您的表使用前缀。此外,如果您在其中一个模型上定义了非默认连接,那么您需要为这两个模型调整 $table。

您还可以为每个模型使用不同的连接,许多功能都可以这样工作,但是您不能依赖 Eloquent 构建的连接:

ModelOne::with('modelTwo')->get(); // works as expected - this is what you asked for
ModelOne::has('modelTwo')->get(); // error, no table found

当然,除非你有相同的架构,但无论如何它都不是你想要的。

【讨论】:

它工作正常。在我的数据库中,真正的列名不是 id 我需要将列的名称添加为belongTo 和hasOne 中的第三个参数。【参考方案5】:

连接不同数据库的两个模型的简单雄辩的方法

class User extends Model 

  public function Company()
  
    return $this->hasOne(Company::class);
  


class Company extends Model 
  protected $connection = 'mysql2';

  public function User()
  
    return $this->belongsTo(User::class);
  

【讨论】:

以上是关于使用 Laravel Eloquent 连接同一服务器上不同数据库中的两个 MySQL 表的主要内容,如果未能解决你的问题,请参考以下文章

Laravel - Eloquent 连接

如何使用 eloquent 在 laravel 中编写多个连接

如何使用 Laravel 4 Eloquent 连接列?

Laravel - 使用 Eloquent 从连接关系模型中选择特定列

使用 Laravel 4 Eloquent 连接列上的列名“”无效?

使用 eloquent laravel 获取连接表数据