引言:为什么Swift开发者需要数据库?
在开发iOS和macOS原生应用时,经常需要不仅将数据存储在本地(Core Data、UserDefaults),还要存储在远程服务器上。这可能是服务器端分析、日志记录、设备间同步或应用程序的完整后端。两种最流行的数据库类型是关系型数据库(PostgreSQL)和文档型数据库(MongoDB)。
在本文中,我们将探讨如何使用流行的库和驱动程序从Swift应用程序连接到PostgreSQL和MongoDB。我们将特别关注实践:安装依赖项、编写查询和处理错误。
1. 从Swift使用PostgreSQL
PostgreSQL是一个强大的关系型数据库管理系统,非常适合需要数据完整性和复杂SQL查询的项目。在Swift中,我们可以通过两种主要方式使用PostgreSQL:
- 通过ORM Fluent(Vapor框架的一部分)——高级方法,适合Web应用程序。
- 直接通过驱动程序(例如
PostgresNIO)——低级控制,适合iOS/macOS应用程序。
我们来看第二种方式,因为它不需要Vapor,适用于普通应用程序。
1.1. 通过PostgresNIO连接到PostgreSQL
在Package.swift中添加依赖项:
dependencies: [ .package(url: "https://github.com/vapor/postgres-nio.git", from: "1.18.0")]连接和执行查询的示例:
import PostgresNIOimport NIOCoreimport NIOPosix
func queryPostgres() async throws { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { try? eventLoopGroup.syncShutdownGracefully() }
let config = PostgresConnection.Configuration( host: "localhost", port: 5432, username: "swift_user", password: "secret", database: "test_db", tls: .disable )
let connection = try await PostgresConnection.connect( on: eventLoopGroup.next(), configuration: config ) defer { try? connection.close() }
let rows = try await connection.query("SELECT id, name FROM users LIMIT 5;", logger: nil) for try await row in rows { let id = try row.decode(Int.self, column: "id") let name = try row.decode(String.self, column: "name") print("ID: \\(id), Name: \\(name)") }}此代码建立与本地PostgreSQL服务器的连接,执行SELECT并输出结果。重要提示:切勿在代码中存储密码——请使用环境变量或Keychain。
1.2. 带参数的插入数据
为防止SQL注入,请使用参数化查询:
let name = "Alice"let age = 30try await connection.query( "INSERT INTO users (name, age) VALUES ($1, $2);", params: [.string(name), .int(age)], logger: nil)2. 从Swift使用MongoDB
MongoDB是一种NoSQL数据库,以类似JSON的文档(BSON)形式存储数据。Swift有一个优秀的驱动程序MongoSwift。
2.1. 安装MongoSwift
在Package.swift中添加:
dependencies: [ .package(url: "https://github.com/mongodb/mongo-swift-driver.git", from: "1.3.0")]2.2. 连接和CRUD操作
连接到本地MongoDB并插入文档的示例:
import MongoSwift
func mongoExample() async throws { let client = try MongoClient("mongodb://localhost:27017") defer { try? client.syncClose() }
let db = client.db("test_database") let collection = db.collection("users")
// 插入文档 let document: Document = ["name": "Bob", "age": 25, "city": "Mosc