- 原文地址:Sharing databases between Laravel applications
- 原文做者:Michael Dyrynda
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:Elliott Zhao
若是您碰巧在 Twitter 上关注了我,您可能已经看到我发表了一些我正在作的平常工做。咱们有一个面向客户的会员区和一个内部 CRM,它们工做在同一个主数据库上。php
CRM 是在我为如今的老板打工以前创建起来的,而会员区是我在 2017 年初做为外包商创建的。会员区自己是一个新的 Laravel 应用程序,而 CRM 则是一个彻底自定义编写的软件。前端
304/5000 做为外包商,我有一个数据库的不完整副本,而且我设法从数据库模式中反向工程 Eloquent 模型,建立工厂,以便可以为会员应用编写测试。mysql
在 2017 年年末,咱们开始将咱们的 CRM 迁移到 Laravel,以便对代码库进行一些现代化改造,为其提供一个标准结构,而且能够轻松地对其进行更改。如今咱们有两个 Laravel 应用程序,咱们开始研究如何在它们之间共享数据。android
数据库模型是最容易处理的部分。为此,咱们使用 Composer 为每一个共享数据库表建立模型建立一个包,并将它们做为 vcs 存储库。这使咱们可以无需经过Packagist发布就能够共享这些模型。ios
这个包中的模型每一个都从它们本身的基础模型扩展而来,它为每一个数据库设置链接,并包含能够将它们链接在一块儿的最少许的逻辑。laravel
咱们试着让包模型仅仅包含互相之间的关系,和一些通用的方法和行为。思路就是是,每一个使用它们的应用程序都会根据须要扩展它们并实现它们本身的特定逻辑。git
迁移是事情开始变得有点棘手的地方。虽然咱们有一个技术上由 CRM 应用程序拥有的数据库,但迁移应该可用于任何将访问其中的数据的应用程序。那么问题就变成了:“哪一个程序负责管理数据库模式?”github
Laravel 在config/database.php
文件中附带多个数据库链接,向您显示各类驱动的可用性。咱们简单的定义几个都使用
mysql` 驱动程序的链接。sql
咱们对管理数据库模式有一些要求:docker
前两个要求至关简单,假设咱们能够经过某种方式解决第三个要求。
我花了很长时间把相似 Artisan 的工具集中在一块儿,这个工具只关注迁移和数据库填充功能 —— Nomad。为了管理许多应用程序的数据库迁移,Nomad 能够被引入独立的 Composer 项目 - 例如 Vagabond。
Vagabond项目随后被做为一个包,您能够将其做为 VCS 存储库使用,并使用服务提供者,指导 Laravel 加载迁移,以及使用它的应用程序中可能存在的全部迁移。
// 在你的 Vagabond 项目的服务提供者中
public function boot()
{
$this->loadMigrationsFrom(dirname(__FILE__).'/../database/migrations');
}
复制代码
咱们在 Nomad 路径中遇到的第一个问题是,若是您没有在迁移文件中指定迁移应该运行的链接,它们将所有在您的默认链接上运行。
// 在您的迁移文件中
public function up()
{
Schema::connection('the_connection')->create('table', function (Blueprint $table)
{
//
}
}
复制代码
第二个问题是,虽然 Laravel 应用程序会在正确的链接上运行迁移,但它会跟踪默认链接上的全部迁移,即若是您为三个不一样的链接运行迁移,则迁移历史记录将所有在应用程序默认链接的 migrations
表。
为何这是个问题?若是您的数据库用户具备足够的权限,它将尝试并在已存在这些表的数据库上反复运行相同的迁移。
若是您有许多不一样的应用程序都使用集中式迁移文件,而且每次都尝试运行相同的迁移,则会出现此问题。
为了解决这个问题,咱们在迁移项目的 database/migrations
文件夹中为每一个链接的迁移建立了文件夹。
database/migrations/
/crm
/gis
/coverage
复制代码
这样作,咱们如今能够为各类迁移命令使用 path
和 database
参数,使咱们可以显式运行每一个链接的迁移: php nomad migrate --database=gis --path=database/migrations/gis
。这确保只运行 gis
迁移,而且在 gis
数据库的 migrations
表中追踪运行迁移的历史记录。
这如今解决了要求1和3; 咱们如今在一个的独立的数据库上使用 Laravel 式迁移,而且咱们还拥有可以运行迁移的独立应用程序。这意味着咱们能够在代码的任何地方运行运行针对特定数据库链接的迁移 a) 能够访问到数据库服务器,而且 b) 拥有具备足够权限的用户。
咱们遇到的另外一个问题是运行测试。
在咱们的测试环境中,咱们使用 Laravel 的 RefreshDatabase
特征,它能够智能地为每一个测试创建并删除整个数据库。然而,在撰写本文时,虽然它正确运行全部迁移,但它只会删除默认数据库链接上的表。
这意味着若是咱们对使用本身的数据库以及共享数据库的应用程序进行测试,则每次测试都将失败,由于 Laravel 会尝试运行未丢弃链接的迁移。对此,Sepehr Lajevardi 有一个解决方案,Keith Damiani 为我指出明路。
Sepehr 的建议中说起的的特性使用一个从待删表的链接数组中查找属性的方法覆盖 Laravel 的默认 refreshTestDatabase
方法。
如今你已经将本身的模型和迁移都打包到了本身的仓库中,这是最后一件你不想作的事情。从项目手动复制到另外一个项目,就是配置自己。
Laravel 实际上很容易将第三方软件包的配置合并到主配置中。在咱们的生产应用程序中,咱们的数据库配置中没有配置任何链接。
相反,这个功能位于每一个数据库链接的服务提供者内部。咱们有一个顶级提供程序,每一个提供程序均可以扩展,默认状况下,每一个提供程序只需定义一个受保护的属性:$connectionName
。
你能够在这里看到这个功能的独立样例。
您须要在应用程序中执行的操做是将服务提供程序添加到您的 config/app.php
文件的提供程序数组中,并为每一个链接定义必要的环境变量。
这个拼图给咱们留下的最后一块是让测试在 CI 管道中运行。对咱们来讲,是 BitBucket。
因为咱们现有的数据库包含不少 ENUM
字段(我不建议使用它们,尤为是由于它们不受这个库的支持 —— doctrine/dbal
—— Laravel 用于迁移功能),咱们必须在咱们的测试环境中使用 MySQL。
在CI管道中使用容器能够轻松启动 MySQL 服务,可是,如何配置多个数据库却并非显而易见的。因为咱们使用的 MariaDB 映像不容许指定绑定的端口,所以多个数据库服务都尝试侦听同一个端口(3306),随后没法启动,从而致使测试套件失败。
解决方案很是简单,只是我以前没发现:在测试套件运行以前使用 MySQL 客户端建立数据库。
你的 bitbucket-pipelines.yml
文件应该以下所示:
image: php:7.1.15
pipelines:
default:
- step:
deployment: test
caches:
- composer
script:
- apt-get update && apt-get install -y unzip git mysql-client
- docker-php-ext-install pdo_mysql
- curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
- cp -n .env.example .env
- export DB_USERNAME=root
- export DB_DATABASE=first_db
- export DB_PASSWORD=supersecret
- export DB_SECOND_USERNAME=root
- export DB_SECOND_DATABASE=second_db
- export DB_SECOND_PASSWORD=supersecret
- export DB_THIRD_USERNAME=root
- export DB_THIRD_DATABASE=third_db
- export DB_THIRD_PASSWORD=supersecret
- composer install
- php artisan key:generate
- mysql -uroot -psupersecret -h127.0.0.1 -e 'create database second_db; create database third_db;'
- vendor/bin/phpunit --colors=always -c phpunit.xml
services:
- mariadb
definitions:
services:
mariadb:
image: mariadb:5.5
environment:
MYSQL_DATABASE: 'first_db'
MYSQL_ROOT_PASSWORD: 'supersecret'
复制代码
export
这几行为咱们的应用程序做用的三个数据库中的每一个数据库进行配置。咱们让 MariaDB 服务使用 MYSQL_DATABASE
环境变量配置第一个数据库,而后使用 MySQL 客户端建立 second_db
和 third_db
。
MYSQL_ROOT_PASSWORD
变量被定义为一个静态字符串,由于我没弄明白如何把随机密码注入部署步骤中,可是若是您知道如何作,请告诉我!
若是您发现本身须要使用共享两个或更多数据库的应用程序,我但愿您在本文中学到了有关管理和使用它们的知识。
涵盖以下内容:
因为应用程序与数据库的分离,咱们必须考虑的一个因素是迁移应该如何以及什么时候运行,由于咱们如今须要将其做为单独的操做来完成。它固然会根据具体状况而有所不一样,咱们须要确保针对每一个应用程序进行测试,以确保不会对数据库引入重大更改。
我花了几个月的时间才把它变成了工做状态,因此我但愿在将来的某个时候,若是你遇到和我类似的状况,我可以为你节省一些时间!
感谢 Keith Damiani 和 Sepehr Lajevardi 指出我拼图中缺失的最后一块。
Jake Bennett 和我在North Meets South网络播客的 episode 43 中讨论了这种迁移行为。
若是您对本文中涵盖的任何内容有任何疑问,或有任何改进建议,请随时在 Twitter 上提出。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。