在本教程中,您将使用Phoenix-Ecto和Mariaex配置现有的Phoenix应用程序连接到MySQL数据库。Ecto是Phoenix应用程序广泛使用的数据库包装器。Mariaex是一个数据库驱动程序,它与Ecto集成并与MySQL和MariaDB数据库进行数据传输。
您还将在开发计算机上创建一个简单的通讯簿,该通讯簿使用数据库并使用edeliver将更改部署到生产服务器。您网站的用户将能够在此通讯录中创建,阅读,更新和删除条目。
要完成本教程,您需要:
通常,Phoenix应用程序不直接建立与数据库的连接并执行SQL查询。而是使用数据库驱动程序连接到所需的数据库,然后使用数据库包装器查询数据库。
数据库驱动程序是一个Elixir应用程序,负责处理使用数据库的普通任务,例如建立连接,关闭连接和执行查询。数据库包装器是数据库驱动程序之上的一个层,允许Elixir程序员使用Elixir代码创建数据库查询,并提供其他功能,如查询组合。
这种分离使模块化应用成为可能。无论使用何种数据库,数据库包装器以及与数据库交互的应用程序代码都大致相同。只需更改数据库驱动程序,Phoenix应用程序就可以使用不同的数据库软件。
应用程序既没有安装Ecto也没有安装Mariaex,您现在将Ecto和Mariaex添加为项目的依赖项。
注意:Phoenix应用程序默认使用PostgreSQL。要使用MySQL数据库生成新应用程序,请使用该命令
mix phx.new --database mysql myproject
首先,切换到包含Phoenix项目的目录。
$ cd ~/myproject
然后打开该mix.exs
文件,其中包含应用程序的依赖项列表。
$ nano mix.exs
找到以下代码块:
~/myproject/mix.exs
defp deps do
[
{:phoenix, "~> 1.3.0"},
{:phoenix_pubsub, "~> 1.0"},
{:phoenix_html, "~> 2.10"},
{:phoenix_live_reload, "~> 1.0", only: :dev},
{:gettext, "~> 0.11"},
{:cowboy, "~> 1.0"},
{:edeliver, "~> 1.4.3"},
{:distillery, "~> 1.4"}
]
end
将Mariaex和Phoenix-Ecto添加为依赖项:
~/myproject/mix.exs
defp deps do
[
{:phoenix, "~> 1.3.0"},
{:phoenix_pubsub, "~> 1.0"},
{:phoenix_html, "~> 2.10"},
{:phoenix_live_reload, "~> 1.0", only: :dev},
{:gettext, "~> 0.11"},
{:cowboy, "~> 1.0"},
{:edeliver, "~> 1.4.3"},
{:distillery, "~> 1.4"},
{:phoenix_ecto, "~> 3.2"},
{:mariaex, "~> 0.8.2"}
]
end
警告:为避免潜在的配置问题,请仔细检查是否在新
phoenix_ecto
条目前面的行末尾添加了逗号(,)。
保存并关闭mix.ex
s。然后运行以下命令下载刚刚添加到项目中的依赖项。
$ mix deps.get
您将在安装依赖项时看到此输出:
Running dependency resolution...
...
* Getting phoenix_ecto (Hex package)
Checking package (https://repo.hex.pm/tarballs/phoenix_ecto-3.3.0.tar)
Fetched package
* Getting mariaex (Hex package)
Checking package (https://repo.hex.pm/tarballs/mariaex-0.8.3.tar)
Fetched package
...
输出显示Mix检查了包之间的兼容性,并从Hex存储库中获取了包及其依赖项。如果此命令失败,请确保已安装Hex并正确修改了mix.exs
。
使用Ecto和Mariaex,您可以设置Ecto存储库。
Phoenix应用程序通过名为Ecto的数据库包装器访问数据库。数据库包装器以项目中的Elixir模块的形式实现。
无论何时需要与数据库交互并使用模块提供的功能,都可以导入此模块。
此存储库模块必须包含Ecto.Repo
宏才能访问由Ecto定义的查询函数。此外,它必须包含用于初始化在名为init
的函数中传递给数据库适配器的选项的代码。
让我们在lib/myproject
目录中名为repo.ex
的文件中创建模块。首先创建文件:
$ nano lib/myproject/repo.ex
将以下代码添加到文件中以定义存储库:
~/myproject/lib/myproject/repo.ex
defmodule Myproject.Repo do
use Ecto.Repo, otp_app: :myproject
@doc """
Dynamically loads the repository url from the
DATABASE_URL environment variable.
"""
def init(_, opts) do
{:ok, Keyword.put(opts, :url, System.get_env("DATABASE_URL"))}
end
end
默认情况下,Phoenix项目定义init
函数,这样如果环境变量DATABASE_URL
存在,那么Ecto将使用环境变量中的配置连接到数据库,而不是使用Phoenix配置文件中的凭据。保存并关闭repo.ex
。
Phoenix项目使用轻量级Elixir进程实现并发和容错。如果他们崩溃,Supervisors会管理这些流程并重新启动它们。Supervisors还可以监督其他supervisors,这种结构称为监督树。
您刚添加的Myproject.Repo
模块实现了一个管理程序,用于管理连接到数据库的进程。
要启动此Supervisors,必须将其添加到项目的监督树中。
打开lib /myproject
文件夹中的application.ex
文件。
$ nano lib/myproject/application.ex
找到定义监督树的以下代码块:
~/myproject/lib/myproject/application.ex
...
children = [
# Start the endpoint when the application starts
supervisor(MyprojectWeb.Endpoint, []),
...
]
...
您可以看到应用程序端点MyprojectWeb.Endpoint
正在作为supervisors启动。添加Myproject.Repo
到此列表:
~/myproject/lib/myproject/myproject.ex
children = [
# Start the Ecto repository
supervisor(Myproject.Repo, []),
# Start the endpoint when the application starts
supervisor(MyprojectWeb.Endpoint, []),
...
]
如果跳过此步骤,Ecto将不会创建与数据库交互的进程,并且任何与数据库交互的尝试都将导致应用程序崩溃。
保存并关闭,application.ex
然后继续。
最后,指定Ecto存储库的应用程序配置,以便可以使用Mix任务,如ecto.create
和ecto.migrate
创建和管理数据库。
在config/config.exs
中打开配置文件。
$ nano config/config.exs
在文件末尾找到以下行:
~/myproject/config/config.exs
import_config "#{Mix.env}.exs"
此行允许特定环境的配置文件(如prod.exs
和test.exs
)在必要时覆盖config.exs
中的设置。在该行上方添加以下代码以配置Ecto存储库:
~/myproject/config/config.exs
...
config :myproject,
ecto_repos: [Myproject.Repo]
...
保存更改并关闭文件。
现在您已配置了Ecto,继续将数据库凭据添加到应用程序。
应用程序连接到数据库有三种情况:开发期间,测试期间和生产期间。
相应地,Phoenix提供了三个特定于环境的配置文件,其中包含与运行应用程序的环境相关的凭据。这些文件位于config项目根目录中的目录中。您将在此步骤中修改这三个文件。
首先,让我们配置开发环境。打开`dev.exs。
$ nano config/dev.exs
添加以下行以将数据库适配器配置为Ecto.Adapters.MySQL
,因为我们使用的是MySQL。
~/myproject/config/dev.exs
config :myproject, Myproject.Repo,
adapter: Ecto.Adapters.MySQL
接下来,在同一代码块中指定所需的数据库名称。
~/myproject/config/dev.exs
config :myproject, Myproject.Repo,
adapter: Ecto.Adapters.MySQL,
database: "myproject_dev"
在这里,我们定义开发数据库名称myproject_dev
。这是Phoenix应用程序用于数据库的命名约定。遵循此约定,将调用生产数据库myproject_prod
和测试数据库myproject_test
。您可以使用自己的命名方案。
现在,提供开发数据库服务器的主机名,用户名和密码。
~/myproject/config/dev.exs
config :myproject, Myproject.Repo,
adapter: Ecto.Adapters.MySQL,
database: "myproject_dev",
username: "root",
password: "password",
hostname: "localhost"
最后,将池大小设置为适当的数字。池大小是应用程序可以拥有的最大数据库连接数。这些连接将在请求之间共享。最佳尺寸取决于您的硬件,但您可以使用它10来启动。
~/myproject/config/dev.exs
config :myproject, Myproject.Repo,
adapter: Ecto.Adapters.MySQL,
username: "root",
password: "password",
database: "myproject_dev",
hostname: "localhost",
pool_size: 10
保存并关闭dev.exs
。
接下来,配置您的测试环境。打开测试环境配置文件test.exs
。
$ nano config/test.exs
在本教程中,我们将在本地数据库服务器上托管开发数据库和测试数据库。因此,测试数据库的配置几乎相同。
我们的pool value指定Ecto.Adapters.SQL.Sandbox
而不是pool_size,这将以沙箱模式运行测试。也就是说,在测试期间使用测试数据库进行的任何事务都将被回滚。这意味着单元测试可以按随机顺序运行,因为数据库在每次测试后都会重置为初始状态。
我们将使用myproject_test
作为数据库名称。
将以下配置添加到test.exs
文件中:
~/myproject/config/test.exs
config :myproject, Myproject.Repo,
adapter: Ecto.Adapters.MySQL,
username: "root",
password: "password",
database: "myproject_test",
hostname: "localhost",
pool: Ecto.Adapters.SQL.Sandbox
保存并关闭test.exs
。最后,要在生产环境中配置应用程序的凭据,请打开生产密钥文件prod.secret.exs
。
$ nano config/prod.secret.exs
将此代码添加到prod.secret.exs
文件中。请注意,我们在这里使用myproject用户名和密码password。。我们将使用此处指定的密码在生产数据库服务器上创建此用户。您需要在此处使用更安全的密码。
~/myproject/config/prod.secret.exs
config :myproject, Myproject.Repo,
adapter: Ecto.Adapters.MySQL,
username: "myapp",
password: "password",
database: "myproject_prod",
hostname: "localhost",
pool_size: 10
保存更改并关闭文件。
出于安全原因,Git不会跟踪此文件,因此您必须手动将其传输到服务器。
$ scp ~/myproject/config/prod.secret.exs sammy@your_server_ip:/home/sammy/app_config/prod.secret.exs
然后调用ecto.create
Mix任务来创建开发数据库。请注意,您不必创建测试数据库,因为Phoenix会在您运行测试时为您执行此操作。
$ mix ecto.create
您将看到以下输出显示Ecto已成功创建数据库:
...
The database for Myproject.Repo has been created
如果您没有看到此输出,请确保您的配置详细信息正确且MySQL正在运行。如果您的应用程序由于任何错误而无法编译,Ecto也会拒绝创建数据库。
现在您已将项目设置为连接到数据库,甚至使用Ecto在开发计算机中创建数据库,您可以继续修改服务器上的数据库。
使用ecto.create
Mix任务,您在开发计算机上创建了一个空数据库。现在,您将为生产服务器执行相同的操作。
遗憾的是,没有任何Mix任务或edeliver命令可以帮助我们实现这一目标,因此您将手动登录服务器并使用MySQL控制台使用SQL命令创建一个空数据库。
通过SSH连接到服务器。
$ ssh sammy@your_server_ip
现在使用root用户和您配置的密码访问MySQL控制台 。
$ mysql -u root -p
登录后,创建生产数据库:
mysql> CREATE DATABASE myproject_prod;
您将看到以下输出,让您知道数据库已创建:
Query OK, 1 row affected (0.00 sec)
接下来,使用用户名myproject和您在上一步中指定的密码为应用创建用户:
mysql> CREATE USER 'myproject'@'localhost' IDENTIFIED BY 'password';
然后让myproject用户访问您创建的数据库:
mysql> GRANT ALL PRIVILEGES ON myproject_prod.* to 'myproject'@'localhost';
最后,应用权限更改:
mysql> FLUSH PRIVILEGES;
输入exit
退出MySQL控制台。 再次键入exit
终止SSH连接。
从现在开始,您很少需要触摸生产数据库,因为您将执行几乎所有操作,例如从本地计算机创建和更改表。
现在,生产数据库已准备就绪,您可以将应用程序重新部署到服务器。
在此步骤中,您将使用新配置的应用程序及其新的Ecto存储库替换与数据库无连接的正在运行的应用程序。此步骤将允许您确保正确配置应用程序并且仍然按预期运行。
打开mix.exs
并增加应用程序版本。版本号可以更轻松地跟踪版本并在必要时回滚到以前的版本。edeliver也可以使用它来升级您的应用程序而无需停机。
$ nano mix.exs
将版本字段增加到适当的值。
~/myproject/mix.exs
def project do
[
app: :myproject,
version: "0.0.3",
elixir: "~> 1.4",
elixirc_paths: elixirc_paths(Mix.env),
compilers: [:phoenix, :gettext] ++ Mix.compilers,
start_permanent: Mix.env == :prod,
deps: deps()
]
end
为了使用edeliver执行数据库迁移,edeliver必须是在项目中启动的最后一个应用程序。找到以下代码块:
~/myproject/mix.exs
def application do
[
mod: {Myproject.Application, []},
extra_applications: [:logger, :runtime_tools]
]
end
添加edeliver到extra_applications
列表的末尾:
~/myproject/mix.exs
def application do
[
mod: {Myproject.Application, []},
extra_applications: [:logger, :runtime_tools, :edeliver]
]
end
保存并关闭mix.exs
。
启动应用程序以确保一切正常并且没有编译错误:
$ mix phx.server
访问http://localhost:4000/addresses
以确保应用程序仍然有效。如果它没有启动,或者您看到编译错误,请查看本教程中的步骤并在继续之前解决它们。
如果一切正常,请在终端中CTRL+C
按两次以停止服务器。
然后,使用Git提交更改。每次更改项目时都必须执行此操作,因为edeliver使用Git将代码从最新提交推送到构建服务器以进行进一步操作。
$ git add .
$ git commit -m "Configured application with database"
最后,使用edeliver更新生产服务器上的应用程序。以下命令将在升级生产计算机上运行的应用程序之前构建和部署项目的最新版本,而无需停机。
$ mix edeliver upgrade production
您将看到以下输出:
EDELIVER MYPROJECT WITH UPGRADE COMMAND
-----> Upgrading to revision 2512398 from branch master
-----> Detecting release versions on production hosts
-----> Deploying upgrades to 1 online hosts
-----> Checking whether installed version 0.0.2 is in release store
-----> Building the upgrade from version 0.0.2
-----> Authorizing hosts
-----> Validating * version 0.0.2 is in local release store
-----> Ensuring hosts are ready to accept git pushes
-----> Pushing new commits with git to: sammy@example.com
-----> Resetting remote hosts to 2512398838c2dcc43de3ccd869779dded4fd5b6b
-----> Cleaning generated files from last build
-----> Checking out 2512398838c2dcc43de3ccd869779dded4fd5b6b
-----> Fetching / Updating dependencies
-----> Compiling sources
-----> Checking version of new release
-----> Uploading archive of release 0.0.2 from local release store
-----> Extracting archive myproject_0.0.2.tar.gz
-----> Removing old releases which were included in upgrade package
-----> Generating release
-----> Removing built release 0.0.2 from remote release directory
-----> Copying release 0.0.3 to local release store
-----> Copying myproject.tar.gz to release store
-----> Upgrading production hosts to version 0.0.3
-----> Authorizing hosts
-----> Uploading archive of release 0.0.3 from local release store
-----> Upgrading release to 0.0.3
UPGRADE DONE!
虽然升级已成功完成,但在重新启动应用程序之前,您将无法运行与数据库相关的edeliver任务。
警告:以下命令将导致应用程序短时间脱机。
$ mix edeliver restart production
你会看到这个输出:
EDELIVER MYPROJECT WITH RESTART COMMAND
-----> restarting production servers
production node:
user : sammy
host : example.com
path : /home/sammy/app_release
response: ok
RESTART DONE!
edeliver告诉我们它已成功重启生产服务器。
要确保已升级应用程序,请运行以下edeliver命令以检索当前正在生产的应用程序的版本。
$ mix edeliver version production
EDELIVER MYPROJECT WITH VERSION COMMAND
-----> getting release versions from production servers
production node:
user : sammy
host : example.com
path : /home/sammy/app_release
response: 0.0.3
VERSION DONE!
-----> getting release versions from production servers
production node:
user : sammy
host : example.com
path : /home/sammy/app_release
response: 0.0.3
VERSION DONE!
输出告诉我们生产服务器正在运行应用程序版本0.0.3。
您还可以访问您的https://example.com
应用程序以确保它正在运行。应用程序不应该有任何可观察到的更改,因为我们没有触及应用程序代码本身。
如果升级成功但无法更新应用程序,请确保您已提交代码并提升了应用程序版本。如果升级命令失败,edeliver将在错误发生时输出它在服务器上执行的bash代码以及错误消息本身。您可以使用这些线索来解决您的问题。
现在您已经为应用程序添加了数据库支持并将其部署到生产环境中,现在您已准备好添加一些使用MySQL的功能。
为了演示如何部署数据库更改,让我们在我们的应用程序中构建一个简单的通讯录并将其部署到生产环境中。
警告:此通讯录可以公开访问,任何人都可以访问和编辑它。在完成本教程后删除该功能,或者限制访问。
运行此命令以生成通讯簿:
$ mix phx.gen.html AddressBook Address addresses name:string email:string zip_code:integer
* creating lib/myproject_web/controllers/address_controller.ex
...
* creating priv/repo/migrations/20180318032834_create_address.exs
Add the resource to your browser scope in web/router.ex:
resources "/addresses", AddressController
Remember to update your repository by running migrations:
$ mix ecto.migrate
Phoenix告诉我们它会自动生成模板文件,测试文件,模型,控制器和迁移文件。它还指示我们将资源添加到路由器文件并更新存储库。
您可以按照在输出中看到的说明进行操作,但通过这样做,您将在单个版本中捆绑应用程序代码升级和数据库迁移。从应用程序部署到生产服务器到迁移生产数据库的时间,这可能导致应用程序的某些部分在生产中失败。在此间隔期间,应用程序代码可能引用数据库中不存在的表或列。
要防止停机和错误,请分两步部署更改:
如果我们不采用这种方法,地址簿的代码将尝试引用我们尚未创建的地址表,我们的应用程序将崩溃。
在我们迁移生产数据库之前,让我们看一下迁移文件。它位于priv/repo/migrations/20180501040548_create_addresses.exs
,尽管根据您创建文件名的时间,文件名将具有不同的日期戳。在编辑器中打开文件:
$ nano priv/repo/migrations/*_create_addresses.exs
Phoenix生成的迁移文件是Elixir模块,其中包含一个名为的函数change
。稍后执行迁移时,将调用此函数。
~/myproject/priv/repo/migrations/20180501040548_create_addresses.exs
defmodule Myproject.Repo.Migrations.CreateAddresses do
use Ecto.Migration
def change do
create table(:addresses) do
add :name, :string
add :email, :string
add :zip_code, :integer
timestamps()
end
end
end
在此函数中,Phoenix生成器已编写代码以创建addresses表以及您提供的字段。此外,该生成器还包括timestamps()为您添加两个字段的功能:inserted_at和updated_at。插入或更新数据时,存储在这些字段中的值会自动更新。
要仅部署迁移文件而不包含应用程序代码,我们将利用edeliver使用Git将项目转移到构建服务器的事实。具体来说,我们只是暂存和提交迁移文件,同时保留其余生成的文件。
在mix.exs中增加应用程序版本,打开mix.exs。
$ nano mix.exs
将应用程序版本增加到适当的值。
~/myproject/mix.exs
def project do
[
app: :myproject,
version: "0.0.4",
...
保存并关闭文件。
现在,使用Git来同步mix.exs
文件和迁移文件。
$ git add mix.exs priv/repo/migrations/*_create_addresses.exs
接下来,提交暂存文件。
$ git commit -m "Adding addresses table to the database"
然后,使用edeliver升级您的生产应用程序。
$ mix edeliver upgrade production
升级完成后,执行以下edeliver命令以迁移生产数据库。
$ mix edeliver migrate production
输出显示迁移已成功运行,并显示迁移文件的时间戳:
EDELIVER MYPROJECT WITH MIGRATE COMMAND
-----> migrateing production servers
production node:
user : sammy
host : example.com
path : /home/sammy/app_release
response: [20180501040548]
MIGRATE DONE!
生产数据库现在有一个名为的空表addresses。
如果没有运行迁移,该response字段将显示[]。如果是这种情况,请确保在再次升级之前使用Git提交了代码。如果问题仍然存在,请通过键入重新启动生产应用程序mix edeliver restart production
,然后再次运行数据库迁移任务。
使用该addresses
表后,我们可以在生成通讯簿并创建新版本时按照Phoenix发布的说明进行操作。
首先,打开lib/myproject_web/router.ex
文件:
$ nano lib/myproject_web/router.ex
找到以下代码块:
~/myproject/lib/myproject_web/router.ex
scope "/", MyprojectWeb do
pipe_through :browser
get "/", PageController, :index
end
插入addresses
资源的路由:
~/myproject/lib/myproject_web/router.ex
scope "/", MyprojectWeb do
pipe_through :browser
get "/", PageController, :index
resources "/addresses", AddressController
end
保存并关闭router.ex
。
接下来,请Ecto对本地数据库进行更改。
$ mix ecto.migrate
输出显示已调用迁移文件中的函数,该函数已成功创建表addresses
。
...
[info] == Running Myproject.Repo.Migrations.CreateAddresses.change/0 forward
[info] create table addresses
[info] == Migrated in 0.0s
现在启动本地开发服务器以测试您的新功能:
$ mix phx.server
将浏览器指向http://localhost:4000/addresses
以查看正在运行的新功能。
如果您对本地工作正常感到满意,请返回终端并按CTRL+C
两次以终止服务器。
现在情况正常,您可以将更改部署到生产环境。打开mix.exs
以更新应用程序版本。
$ nano mix.exs
将版本字段增加到适当的值。
~/myproject/mix.exs
def project do
[
app: :myproject,
version: "0.0.5",
elixir: "~> 1.4",
elixirc_paths: elixirc_paths(Mix.env),
compilers: [:phoenix, :gettext] ++ Mix.compilers,
start_permanent: Mix.env == :prod,
deps: deps()
]
end
保存并关闭mix.exs
。
使用Git提交您的更改。这一次,暂存所有文件。
git add .
git commit -m "Added application code for address book"
使用edeliver升级生产应用程序。
$ mix edeliver upgrade production
更新完成后,您可以访问https://example.com/addresses
上的新功能。
有了它,您已成功升级了生产应用程序和数据库。
在本文中,您将Phoenix应用程序配置为使用MySQL数据库,并使用edeliver和Ecto迁移来更改生产数据库。您要对生产数据库所做的任何更改都是通过Ecto迁移文件完成的。这样可以更轻松地回滚更改并跟踪数据库随时间的更改。要了解有关Ecto迁移以及如何执行复杂数据库操作的更多信息,请参阅官方Ecto迁移文档。
参考文献:《How to Deploy Elixir-Phoenix Applications with MySQL on Ubuntu 16.04》
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。