Swift写服务端六:安装PostgreSQL并使用Vapor远程连接

1.为什么安装PostgreSQL

因为Vapor官方推荐使用该数据库。

2.安装步骤

安装postgresql

sudo apt-get install postgresql

安装好后,默认已经开启了postgresql,使用service命令查看postgresql运行状态

yuhua@sweet-story-2:~$ service postgresql status
● postgresql.service - PostgreSQL RDBMS
   Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; vendor prese
   Active: active (exited) since Mon 2022-06-13 21:45:58 EDT; 1min 48s ago
 Main PID: 2532 (code=exited, status=0/SUCCESS)
    Tasks: 0 (limit: 1175)
   CGroup: /system.slice/postgresql.service

postgresql安装好后,会创建出一个linux的用户,名字是:postgres,首次登录postgresql数据库时,必须使用该用户登录。所以使用该用户登录postgresql。

  • 不需要管这个linux用户,该用户是无法登录的。
yuhua@sweet-story-2:~$ sudo -u postgres psql
[sudo] password for yuhua: 
psql (10.21 (Ubuntu 10.21-0ubuntu0.18.04.1))
Type "help" for help.

postgres=# 

创建用户的同时,还自动创建出了一个数据库: postgres,首次使用postgres用户登录时,自动连接上了该数据库。可以使用\conninfo命令查看连接信息。

postgres=# \conninfo
You are connected to database "postgres" as user "postgres" via socket in "/var/run/postgresql" at port "5432".

使用\l命令查看所有数据库信息。

postgres=# \l
                                  List of databases
   Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
-----------+----------+----------+-------------+-------------+-----------------------
 postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
(3 rows)

使用\du命令可以查看所有能够操作postgresql数据库的用户列表。

postgres=# \du
                                   List of roles
 Role name |                         Attributes                         | Member of 
-----------+------------------------------------------------------------+-----------
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}

由于数据库默认的postgres用户是没有设置密码的,我们需要给他设置密码

postgres=# \password postgres
Enter new password for user "postgres": 输入密码
Enter it again: 再次输入密码

密码改好后,创建出项目需要的数据库。

// 创建数据,注意末尾的分号
postgres=# CREATE DATABASE sample_code;
CREATE DATABASE
// 切换到创建的数据库
postgres=# \c sample_code
You are now connected to database "sample_code" as user "postgres".
// 查看是否连接正确
sample_code=# \conninfo
You are connected to database "sample_code" as user "postgres" via socket in "/var/run/postgresql" at port "5432".

退出postgresql

\q

3.设置nginx反向代理PostgreSQL

现在外部是无法连接到PostgreSQL,我们通过nginx反向代理让它能够被访问。将下面内容写入/etc/nginx/nginx.conf中,注意与http是同一级的。

stream {
        upstream pgsql {
                server 127.0.0.1:5432;
        }
        server {
                listen 12345;
                proxy_connect_timeout 30s;
                proxy_timeout 30s;
                proxy_pass pgsql;
        }
}

重启nginx。

sudo systemctl restart nginx

4.使用工具连接

接下来我使用VS Code的PostgreSQL插件进行连接,可以看到如下结果,说明连接成功了。


image.png

5.Vapor项目远程连接PostgreSQL

我没有在本机安装PostgreSQL,打算直接写代码的时候就远程连接然后进行编写。
首先,SampleCode项目Package.swift中添加Fluent和PostgreSQL Driver。


image.png
import PackageDescription

let package = Package(
    name: "SampleCode",
    platforms: [
       .macOS(.v12)
    ],
    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: "Vapor", package: "vapor"),
                .product(name: "Fluent", package: "fluent"),
                .product(name: "FluentPostgresDriver", package: "fluent-postgres-driver")
            ],
            swiftSettings: [
                // Enable better optimizations when building in Release configuration. Despite the use of
                // the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release
                // builds. See <https://github.com/swift-server/guides/blob/main/docs/building.md#building-for-production> for details.
                .unsafeFlags(["-cross-module-optimization"], .when(configuration: .release))
            ]
        ),
        .executableTarget(name: "Run", dependencies: [.target(name: "App")]),
        .testTarget(name: "AppTests", dependencies: [
            .target(name: "App"),
            .product(name: "XCTVapor", package: "vapor"),
        ])
    ]
)

依赖拉取完毕后,增加模型类Menu.swift。

import Vapor
import Fluent

final class Menu: Model {
    // 数据库表名
    static let schema = "menu"
    
    // 使用UUID作为id,没有使用自增id,是为了适配NoSQL
    @ID
    var id: UUID?
    
    // 标题
    @Field(key: "title")
    var title: String
    
    // 父id,数据库字段名为super_id,名为superId,两者可以不一样。
    // 如果字段是可选的,需要使用OptionalField
    @OptionalField(key: "super_id")
    var superId: UUID?
    
    // 必须要有一个空的初始化方法
    init() {}
    
    // 自定义的初始化方法
    init(id: UUID? = nil, title: String, superId: UUID? = nil) {
        self.id = id
        self.title = title
        self.superId = superId
    }
}

然后增加数据库创建类CreateMenu.swift结构体。


import Fluent

struct CreateMenu: Migration {
    func prepare(on database: Database) -> EventLoopFuture<Void> {
        database.schema("menu")
            .id()
            .field("title", .string, .required)
            .field("super_id", .uuid)
            .create()
    }
    
    func revert(on database: Database) -> EventLoopFuture<Void> {
        database.schema("menu").delete()
    }
}

有些数据不方便上传GitHub,我们可以放到环境变量中。在项目目录下创建.env文件夹,然后添加development和production文件。看名字就知道一个文件对应了一个开发环境。在文件内我们把数据库的地址,端口号,账号密码等信息写进去,为了安全,.env文件夹不要传到GitHub。


image.png

然后去configure.swift配置数据库。

import Vapor
import Fluent
import FluentPostgresDriver

// configures your application
public func configure(_ app: Application) throws {
    // uncomment to serve files from /Public folder
    // app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))

    // 连接数据库
    app.databases.use(.postgres(
        hostname: Environment.get("DATABASE_HOST") ?? "",
        port: Environment.get("DATABASE_PORT").flatMap(Int.init(_:)) ?? 0,
        username: Environment.get("DATABASE_USERNAME") ?? "",
        password: Environment.get("DATABASE_PASSWORD") ?? "",
        database: Environment.get("DATABASE_NAME") ?? ""
    ), as: .psql)
    
    // 创建表
    app.migrations.add(CreateMenu())
    // 设置打印等级
    app.logger.logLevel = .debug
    // 等待数据库操作完毕
    try app.autoMigrate().wait()
    
    // register routes
    try routes(app)
}

其中Environment.get()就是去读取配置文件的内容。如果是xcode运行的话,还需要把配置文件的内容在Run Scheme中配置一遍。


image.png

运行起来,然后去vs code的postgresql查看工具查看,可以看到数据库多出了一个表,表示项目正常运行,同时创建出了表。


image.png

6.更多PostgreSQL命令

psql -d database -U user -W 通过指定用户连接指定数据库
psql -h host -d database -U user -W 通过指定用户连接指定地址的指定数据库
psql -U user -h host “dbname=db sslmode=require”    通过ssh连接
\c dbname   切换数据库    
\l  列出所有数据库  
\dt 列出所有可用的数据库   
\d table_name   显示某个数据库的信息   
\dn 当前连接数据库信息
\df 当前连接数据库的方法
\dv 当前连接数据库的内容 
\du 当前连接数据库的用户 
SELECT version();   数据版本信息
\g  执行最后一条命令     
\s  展示命令列表
\s filename 保存历史命令 
\i filename 保存历史命令到文件 
\?  所有可用的命令
\h  命令帮助
\e  自定义命令 
\a  切换输出样式   
\H  切换输出为HTML样式
\q  退出
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容