切换到 PostgreSQL 封面
Vapor 大型教程

切换到 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 等。

macOS 上:右键点击顶部状态栏的 Docker 图标 → Preferences → Daemon 标签下的 Registry mirrors 列表里加入 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


本系列其他文章