切换到 PostgreSQL
之前为了方便一直用基于文件的 SQLite,但它不支持外键约束。本文用 Docker 起 PostgreSQL,并在工程里改接 FluentPostgreSQL,验证外键约束真正生效。
为什么换库
之前图方便一直用的 SQLite 是基于文件的数据库系统,功能上有所缺失。之前做父子关系试验时就发现 SQLite 不支持外键约束,加了和没加一样。所以决定切换到 PostgreSQL 来验证。
用 Docker 起 PostgreSQL
我们用 Docker 来部署 PostgreSQL。Docker 的安装请自行参考官网最新文档。在 Shell 中跑下面这段命令即可布置好 PostgreSQL 环境:
docker run --name postgres -e POSTGRES_DB=vapor \
-e POSTGRES_USER=vapor -e POSTGRES_PASSWORD=password \
-p 5432:5432 -d postgres
在 macOS 上配置数据库
macOS 上也可以使用作者写好的脚本安装:
$ wget https://raw.githubusercontent.com/wangzhizhou/TILApp-BackEnd/master/database-config-mac.sh
$ chmod u+x database-config-mac.sh
$ ./database-config-mac.sh -i
$ ./database-config-mac.sh -d
国内 Docker 镜像加速
国内可使用 DaoCloud 加速。Linux 下执行:
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io
该脚本会把 --registry-mirror 写入 Docker 配置文件 /etc/docker/daemon.json,适用于 Ubuntu 14.04、Debian、CentOS 6/7、Fedora、Arch Linux、openSUSE Leap 42.1 等。
http://f1361db2.m.daocloud.io,点击 Apply & Restart 生效。Windows 上:右键状态栏 Docker 图标,在 Docker Daemon 标签页的 json 里把该地址加入 "registry-mirrors" 数组,点击 Apply。工程中切换 FluentPostgreSQL
先在 Package.swift 加入 fluent-postgresql 包:
// PostgreSQL
.package(url: "https://github.com/vapor/fluent-postgresql", from: "1.0.0")
...
.target(name: "App", dependencies: ["FluentPostgreSQL", "Vapor"]),
在 configure.swift 中注册 FluentPostgreSQLProvider,并配置数据库连接与迁移:
import FluentPostgreSQL
...
try services.register(FluentPostgreSQLProvider())
...
/// Register the configured SQLite database to the database config.
let databaseConfig = PostgreSQLDatabaseConfig(hostname: "localhost",
port: 5432,
username: "vapor",
database: "vapor",
password: "password")
let database = PostgreSQLDatabase(config: databaseConfig)
var databases = DatabasesConfig()
databases.add(database: database, as: .psql)
services.register(databases)
/// Configure migrations
var migrations = MigrationConfig()
migrations.add(model: User.self, database: .psql)
migrations.add(model: Acronym.self, database: .psql)
services.register(migrations)
在 Acronym 模型里改用 PostgreSQL 相关协议,并在迁移中加上指向 User.id 的外键约束:
import FluentPostgreSQL
...
extension Acronym: PostgreSQLModel {}
...
extension Acronym: Migration {
static func prepare(on connection: PostgreSQLConnection) -> Future<Void> {
// 创建 Acronym 在数据库中的表
return Database.create(self, on: connection) { (builder) in
// 添加 Acronym 所有属性到表中
try addProperties(to: builder)
// 这一句添加了 Acronym.userID 到 User.id 的外键约束
builder.reference(from: \.userID, to: \User.id)
}
}
}
...
import FluentPostgreSQL
...
extension User: PostgreSQLUUIDModel {}
运行程序并验证外键约束是否生效。从错误信息可以看出,PostgreSQL 确实支持外键约束。
什么是外键约束
外键必须是另一个表中的主键。外键的用途是确保数据的完整性:因为我们在 Acronym 中定义了外键 userID 指向 User 表的主键 id,所以要创建一个 Acronym 时,它对应的 User 必须已经存在才能创建成功;要删除一个 User 时,需要先把该 User 下的所有 Acronym 删掉,才能删除该 User。