第6章:配置数据库¶
数据库允许你在你的应用程序中持久保存数据。在本章中,你将学习如何配置你的Vapor
应用程序与你选择的数据库集成。
本章以及本书的大部分内容都使用Docker
来托管数据库。Docker
是一种容器化技术,它允许你在你的机器上运行独立的镜像,而没有虚拟机的开销。你可以旋转不同的数据库,不用担心安装依赖性或数据库之间的相互干扰。
为什么使用数据库?¶
数据库为存储和检索数据提供了一种可靠的、高性能的手段。如果你的应用程序将信息存储在内存中,那么当你停止应用程序时,它就会丢失。将存储与你的应用程序解耦是一个很好的做法,因为这允许你在多个实例中扩展你的应用程序,所有这些实例都由同一个数据库支持。事实上,大多数托管解决方案都没有持久性文件存储。
选择一个数据库¶
Vapor
有官方的、Swift
原生的驱动程序:
SQLite
MySQL
PostgreSQL
MongoDB
有两种类型的数据库:关系型,或SQL
数据库,以及非关系型,或NoSQL
数据库。关系型数据库将其数据存储在具有定义列的结构化表格中。它们在存储和查询数据方面很有效,因为这些数据的结构是预先知道的。你用一种结构化查询语言(SQL
)来创建和查询表格,允许你从多个相关的表格中检索数据。例如,如果你在一个表中有一个宠物列表,在另一个表中有一个主人列表,你可以用一个查询来检索宠物列表和它们主人的名字。
虽然关系型数据库适合于刚性结构,但如果你必须改变这种结构,这可能是一个问题。最近,NoSQL
数据库作为一种存储大量非结构化数据的方式变得很流行。例如,社交网络可以将设置、图像、位置、状态和指标全部存储在一个文件中。这使其比传统数据库有更大的灵活性。
MySQL
和PostgreSQL
是关系型数据库的例子。MongoDB
是一个非关系型数据库的例子。Fluent
支持这两种类型的数据库,有不同的底层驱动。但要注意的是,你不能直接用Fluent
来充分利用你选择的数据库。Fluent
必须支持这两种类型的数据库,并为每个数据库提供同等的功能。不过你可以为某个特定的数据库扩展Fluent
的功能,比如说增加对PostGIS
的支持。如果需要的话,也很容易进行原始查询。
SQLite
¶
SQLite
是一个简单的、基于文件的关系数据库系统。它被设计成嵌入到一个应用程序中,对单进程应用程序(如iOS
应用程序)很有用。它依赖于文件锁来保持数据库的完整性,所以它不适合写密集型的应用程序。这也意味着你不能跨服务器使用它。然而,它是一个很好的数据库,适用于测试和原型开发的应用程序。
MySQL
¶
MySQL
是另一个开源的关系型数据库,由LAMP
网络应用程序栈(Linux
、Apache
、MySQL
、PHP
)普及。它已经成为最受欢迎的数据库,因为它易于使用,并得到大多数云提供商和网站建设者的支持。
PostgreSQL
¶
PostgreSQL
--经常被简称为Postgres
--是一个开源的关系型数据库系统,专注于可扩展性和标准,是为企业使用设计的。Postgres
也有对几何基元的本地支持,如坐标。Fluent
支持这些基元,也支持将嵌套类型,如字典,直接保存到Postgres
中。
MongoDB
¶
MongoDB
是一个流行的开源、基于文档的非关系型数据库,旨在处理大量的非结构化数据,并具有极高的可扩展性。它将数据存储在类似JSON
的文件中,采用人类可读的格式,不需要任何特定的结构。
配置Vapor
¶
配置Vapor
应用程序以使用数据库的步骤与所有支持的数据库相同,如下所示。
- 将
Fluent Provider
作为一个依赖项添加到项目中。 - 配置数据库。
本章中的每个数据库配方都以TILApp
开始,就像你在第5章"Fluent & Persisting Models"
中留下的那样。你还需要安装并运行Docker
。访问https://www.docker.com/get-docker,按照说明进行安装。工具箱允许你选择支持哪一个数据库,但你将学习如何手动选择一个不同的数据库。
SQLite
¶
与其他数据库类型不同,SQLite
不需要你运行数据库服务器,因为SQLite
使用本地文件。打开你项目目录中的Package.swift
。用下面的内容替换:
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "TILApp",
platforms: [
.macOS(.v10_15)
],
dependencies: [
.package(
url: "https://github.com/vapor/vapor.git",
from: "4.0.0"),
.package(
url: "https://github.com/vapor/fluent.git",
from: "4.0.0"),
// 1
.package(
url: "https://github.com/vapor/fluent-sqlite-driver.git",
from: "4.0.0")
],
targets: [
.target(
name: "App",
dependencies: [
.product(name: "Fluent", package: "fluent"),
// 2
.product(
name: "FluentSQLiteDriver",
package: "fluent-sqlite-driver"),
.product(name: "Vapor", package: "vapor")
],
swiftSettings: [
.unsafeFlags(
["-cross-module-optimization"],
.when(configuration: .release))
]
),
.target(name: "Run", dependencies: [.target(name: "App")]),
.testTarget(name: "AppTests", dependencies: [
.target(name: "App"),
.product(name: "XCTVapor", package: "vapor"),
])
]
)
下面是这个的作用:
- 指定
FluentSQLiteDriver
作为软件包的依赖。 - 指定
App
目标依赖FluentSQLiteDriver
,以确保其链接正确。
像其他数据库一样,数据库配置发生在Sources/App/configure.swift
。要切换到SQLite
,请将该文件的内容替换为:
import Fluent
// 1
import FluentSQLiteDriver
import Vapor
// configures your application
public func configure(_ app: Application) throws {
app.databases.use(.sqlite(.memory), as: .sqlite)
app.migrations.add(CreateAcronym())
app.logger.logLevel = .debug
try app.autoMigrate().wait()
// register routes
try routes(app)
}
这些变化是:
- 导入
FluentSQLiteDriver
。 - 配置应用程序使用具有
.sqlite
标识符的内存SQLite
数据库。
你可以将SQLite
配置为使用内存数据库--这意味着应用程序在每次运行时都会创建一个新的数据库实例。该数据库驻留在内存中,它不被持久化到磁盘上,并且在应用程序终止时丢失。这对于测试和原型设计是很有用的。
如果你想用SQLite
进行持久化存储,请提供SQLiteDatabase
的路径,如下所示:
app.databases.use(.sqlite(.file("db.sqlite")), as: .sqlite)
如果文件不存在,这将在指定路径下创建一个数据库文件。如果该文件存在,Fluent
就会使用它。
确保你将部署目标设置为My Mac
,然后构建并运行你的应用程序。
寻找控制台中的迁移信息。
MySQL
¶
要用MySQL
进行测试,在Docker
容器中运行MySQL
服务器。在终端输入以下命令:
docker run --name mysql \
-e MYSQL_USER=vapor_username \
-e MYSQL_PASSWORD=vapor_password \
-e MYSQL_DATABASE=vapor_database \
-e MYSQL_RANDOM_ROOT_PASSWORD=yes \
-p 3306:3306 -d mysql
下面是这个的作用:
- 运行一个名为
mysql
的新容器。 - 通过环境变量指定数据库名称、用户名和密码。
- 设置
MYSQL_RANDOM_ROOT_PASSWORD
,将所需的根密码设置为一个随机值。 - 允许应用程序在其默认端口连接到
MySQL
服务器:3306
. - 在后台作为一个守护程序运行服务器。
- 为这个容器使用名为
mysql
的Docker
镜像。如果该镜像在你的机器上不存在,Docker
会自动下载它。
要检查你的数据库是否在运行,在终端输入以下内容,以列出所有活动的容器:
docker ps
现在,MySQL
正在运行,设置你的Vapor
应用程序。打开Package.swift
;用下面的内容替换它:
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "TILApp",
platforms: [
.macOS(.v10_15)
],
dependencies: [
.package(
url: "https://github.com/vapor/vapor.git",
from: "4.0.0"),
.package(
url: "https://github.com/vapor/fluent.git",
from: "4.0.0"),
// 1
.package(
url: "https://github.com/vapor/fluent-mysql-driver.git",
from: "4.0.0")
],
targets: [
.target(
name: "App",
dependencies: [
.product(name: "Fluent", package: "fluent"),
// 2
.product(
name: "FluentMySQLDriver",
package: "fluent-mysql-driver"),
.product(name: "Vapor", package: "vapor")
],
swiftSettings: [
.unsafeFlags(
["-cross-module-optimization"],
.when(configuration: .release))
]
),
.target(name: "Run", dependencies: [.target(name: "App")]),
.testTarget(name: "AppTests", dependencies: [
.target(name: "App"),
.product(name: "XCTVapor", package: "vapor"),
])
]
)
下面是这个的作用:
- 指定
FluentMySQLDriver
作为软件包的依赖。 - 指定
App
目标依赖FluentMySQLDriver
以确保其链接正确。
接下来,打开configure.swift
。要切换到MySQL
,将内容替换为以下内容:
import Fluent
// 1
import FluentMySQLDriver
import Vapor
// configures your application
public func configure(_ app: Application) throws {
// 2
app.databases.use(.mysql(
hostname: Environment.get("DATABASE_HOST") ?? "localhost",
username: Environment.get("DATABASE_USERNAME")
?? "vapor_username",
password: Environment.get("DATABASE_PASSWORD")
?? "vapor_password",
database: Environment.get("DATABASE_NAME")
?? "vapor_database",
tlsConfiguration: .forClient(certificateVerification: .none)
), as: .mysql)
app.migrations.add(CreateAcronym())
app.logger.logLevel = .debug
try app.autoMigrate().wait()
// register routes
try routes(app)
}
这些变化是:
- 导入
FluentMySQLDriver
。 - 使用
.mysql
标识符在应用程序中注册数据库。你使用环境变量提供数据库的凭证。如果环境变量不存在,配置使用你提供给docker
的相同的硬编码值。
Note
MySQL
默认使用TLS
连接。当在Docker
中运行时,MySQL
会生成一个自签名的证书。你的应用程序不知道这个证书。为了让你的应用程序能够连接,你需要禁用证书验证。你一定不能在生产应用中使用这个。你应该为生产应用提供信任的证书。
确保你将部署目标设置为My Mac
,然后构建并运行你的应用程序。
寻找控制台中的迁移信息。
MongoDB
¶
要用MongoDB
进行测试,在Docker
容器中运行MongoDB
服务器。在终端输入以下命令:
docker run --name mongo \
-e MONGO_INITDB_DATABASE=vapor \
-p 27017:27017 -d mongo
下面是这个的作用:
- 运行一个名为
mongo
的新容器。 - 通过一个环境变量指定数据库名称。
- 允许应用程序连接到
MongoDB
服务器的默认端口:27017
. - 在后台作为一个守护程序运行服务器。
- 为这个容器使用名为
mongo
的Docker
镜像。如果该镜像在你的机器上不存在,Docker
会自动下载它。
要检查你的数据库是否在运行,在终端输入以下内容,以列出所有活动的容器:
docker ps
现在MongoDB
正在运行,设置你的Vapor
应用程序。打开Package.swift
;将其内容改为以下内容:
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "TILApp",
platforms: [
.macOS(.v10_15)
],
dependencies: [
.package(
url: "https://github.com/vapor/vapor.git",
from: "4.0.0"),
.package(
url: "https://github.com/vapor/fluent.git",
from: "4.0.0"),
// 1
.package(
url: "https://github.com/vapor/fluent-mongo-driver.git",
from: "1.0.0")
],
targets: [
.target(
name: "App",
dependencies: [
.product(name: "Fluent", package: "fluent"),
// 2
.product(
name: "FluentMongoDriver",
package: "fluent-mongo-driver"),
.product(name: "Vapor", package: "vapor")
],
swiftSettings: [
.unsafeFlags(
["-cross-module-optimization"],
.when(configuration: .release))
]
),
.target(name: "Run", dependencies: [.target(name: "App")]),
.testTarget(name: "AppTests", dependencies: [
.target(name: "App"),
.product(name: "XCTVapor", package: "vapor"),
])
]
)
下面是这个的作用:
- 指定
FluentMongoDriver
作为软件包的依赖关系。 - 指定
App
目标依赖FluentMongoDriver
以确保其正确链接。
接下来,打开configure.swift
。要切换到MongoDB
,请将内容替换为以下内容:
import Fluent
// 1
import FluentMongoDriver
import Vapor
// configures your application
public func configure(_ app: Application) throws {
// 2
try app.databases.use(.mongo(
connectionString: "mongodb://localhost:27017/vapor"),
as: .mongo)
app.migrations.add(CreateAcronym())
app.logger.logLevel = .debug
try app.autoMigrate().wait()
// register routes
try routes(app)
}
这些变化是:
- 导入
FluentMongoDriver
。 - 使用
.mongo
标识符在应用程序中注册数据库。MongoDB
使用一个连接URL
,如图所示。该URL指定了主机--在这里是localhost
--端口和数据库的路径。该路径与提供给Docker
的数据库名称相同。默认情况下,MongoDB
不需要认证,但如果需要,你可以在这里提供认证。
确保你将部署目标设置为My Mac
,然后构建并运行你的应用程序。
寻找控制台中的迁移信息。
PostgreSQL
¶
你创建的第5章"Fluent
与持久化模型 "中的Vapor
应用已经使用了PostgreSQL
。记住,你在Docker
中用下面的命令在终端创建了一个PostgreSQL
数据库:
docker run --name postgres \
-e POSTGRES_DB=vapor_database \
-e POSTGRES_USER=vapor_username \
-e POSTGRES_PASSWORD=vapor_password \
-p 5432:5432 -d postgres
以下是这样做的:
- 运行一个名为
postgres
的新容器。 - 通过环境变量指定数据库名称、用户名和密码。
- 允许应用程序连接到
Postgres
服务器的默认端口:5432
. - 在后台作为一个守护程序运行服务器。
- 为这个容器使用名为
postgres
的Docker
镜像。如果你的机器上没有这个镜像,Docker
会自动下载它。
要检查你的数据库是否在运行,在终端输入以下内容,以列出所有活动的容器:
docker ps
要了解你的Vapor
应用程序如何使用PostgreSQL
。打开Package.swift
。它看起来将类似于下面:
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "TILApp",
platforms: [
.macOS(.v10_15)
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(
url: "https://github.com/vapor/vapor.git",
from: "4.0.0"),
.package(
url: "https://github.com/vapor/fluent.git",
from: "4.0.0"),
.package(
url:
"https://github.com/vapor/fluent-postgres-driver.git",
from: "2.0.0")
],
targets: [
.target(
name: "App",
dependencies: [
.product(name: "Fluent", package: "fluent"),
.product(
name: "FluentPostgresDriver",
package: "fluent-postgres-driver"),
.product(name: "Vapor", package: "vapor")
],
swiftSettings: [
.unsafeFlags(
["-cross-module-optimization"],
.when(configuration: .release))
]
),
.target(name: "Run", dependencies: [.target(name: "App")]),
.testTarget(name: "AppTests", dependencies: [
.target(name: "App"),
.product(name: "XCTVapor", package: "vapor"),
])
]
)
你可以看到你的应用程序依赖于FluentPostgresDriver
。数据库配置发生在configure.swift
中,就像所有其他的数据库类型一样。你的configure.swift
应该包含以下内容:
import Fluent
// 1
import FluentPostgresDriver
import Vapor
// configures your application
public func configure(_ app: Application) throws {
// 2
app.databases.use(.postgres(
hostname: Environment.get("DATABASE_HOST")
?? "localhost",
username: Environment.get("DATABASE_USERNAME")
?? "vapor_username",
password: Environment.get("DATABASE_PASSWORD")
?? "vapor_password",
database: Environment.get("DATABASE_NAME")
?? "vapor_database"
), as: .psql)
// 3
app.migrations.add(CreateAcronym())
app.logger.logLevel = .debug
// 4
try app.autoMigrate().wait()
// register routes
try routes(app)
}
下面是这个的作用:
- 导入
FluentPostgresDriver
。 - 用
.psql
标识符配置PostgreSQL
数据库。这要么使用作为环境变量传递的证书,要么使用与传递给Docker
的证书一致的硬编码证书。 - 将
CreateAcronym
添加到应用程序的迁移列表中。 - 在应用启动时自动运行迁移程序。
当你第一次运行你的应用程序时,你会看到迁移的运行:
接下来去哪?¶
在本章中,你已经学会了如何为你的应用程序配置一个数据库。下一章将介绍CRUD
操作,以便你可以创建、检索、更新和删除你的缩写。