PostgreSQL 教程: 使用 Golang 连接到 PostgreSQL

八月 8, 2024

摘要:本教程介绍如何将 PostgreSQL 与编程语言 Golang(Go)一起使用。在展示了如何开始使用 Go 的对象关系映射器之后,会提供一个使用 Go 设置 PostgreSQL 数据库的示例。

目录

Golang(或简称为“Go”)是一种强大的类 C/C++ 编程语言,自 2009 年发布以来引起了人们的广泛关注。它由 Google 创建,并在 Google 内部广泛使用,有些软件工程师选择使用 Go 而不是 C/C++ 和 Java 等更传统的语言,因为它的语法和功能更直观。在大多数情况下,这些开发人员都表示选择 Go 是一个很好的选择,他们可能不会再回去了。为了继续他们的良好选择,他们经常使用世界上最强大的开源数据库 PostgreSQL,来支持他们的应用程序。本教程将讨论如何使用 Go 和 PostgreSQL 一起工作。

连接器

在本文中,我们将使用 GORM,这是一个非常强大的为 Go 编写的对象关系映射器(ORM),底层是通过 Go 的 “lib/pq” 模块连接到 PostgreSQL。使用 “lib/pq” 非常简单(对于我们来说可能太简单了,无需写一篇完整的文章)。欲了解更多信息,请访问 https://godoc.org/github.com/lib/pq

开始上手

我们假设您的机器上安装了 Go,因为有几种方法可以做到这一点,但是要涵盖每个操作系统和方法的话,就超出了本文的范围。安装 Go 后,您需要安装 GORM 及其一些依赖项:

go get github.com/jinzhu/gorm
go get github.com/gorilla/mux
go get github.com/lib/pq
go get github.com/rs/cors

简单示例

虽然有许多框架可供 Go 使用,但它们中的大多数都没有涉及将模型与路由等分离的细节。所有这一切都取决于开发人员,虽然您当然可以将它们拆分为不同的文件和目录,但我们将在这里给出一个简单的单文件示例

首先,您需要导入 GORM 包:

package main

import (
  "encoding/json"
  "log"
  "net/http"
  "github.com/gorilla/mux"
  "github.com/jinzhu/gorm"
  "github.com/rs/cors"
  _ "github.com/jinzhu/gorm/dialects/postgres"
)

接下来,您需要将 Driver 和 Car 表定义为结构体:

type Driver struct {
  gorm.Model
  Name     string
  License  string
  Cars     []Car
}

type Car struct {
  gorm.Model
  Year       int
  Make       string
  ModelName  string
  DriverID   int
}

请注意,我们已经为 Car 创建了一个引用,以具有驾驶员/所有者。GORM 不会在数据库端创建外键,但您可以在软件中定义一对多的关系(请注意,Driver 在其模型定义中可以有多个 Car)。

接下来,我们将告诉 Go 为我们插入一些数据:

var db *gorm.DB
var err error

var (
    drivers = []Driver {
        {Name: "Jimmy Johnson", License: "ABC123"},
        {Name: "Howard Hills",  License: "XYZ789"},
        {Name: "Craig Colbin",  License: "DEF333"},
    }

    cars = []Car {
        {Year: 2000, Make: "Toyota", ModelName: "Tundra", DriverID: 1},
        {Year: 2001, Make: "Honda",  ModelName: "Accord", DriverID: 1},
        {Year: 2002, Make: "Nissan", ModelName: "Sentra", DriverID: 2},
        {Year: 2003, Make: "Ford",   ModelName: "F-150",  DriverID: 3},
    }
)

然后,你需要告诉 Go 如何处理进来的 HTTP 请求:

func main() {
  router := mux.NewRouter()
  db, err = gorm.Open( "postgres", "host=db port=5432 user=postgres dbname=postgres sslmode=disable password=postgres")

  if err != nil {
    panic("failed to connect database")
  }

  defer db.Close()
  db.AutoMigrate(&Driver{})
  db.AutoMigrate(&Car{})

  for index := range cars {
      db.Create(&cars[index])
  }

  for index := range drivers {
      db.Create(&drivers[index])
  }

  router.HandleFunc("/cars", GetCars).Methods("GET")
  router.HandleFunc("/cars/{id}", GetCar).Methods("GET")
  router.HandleFunc("/drivers/{id}", GetDriver).Methods("GET")
  router.HandleFunc("/cars/{id}", DeleteCar).Methods("DELETE")

  handler := cors.Default().Handler(router)
  log.Fatal(http.ListenAndServe(":8080", handler))
}

最后,您需要定义应用程序将如何处理 HTTP 请求:

func GetCars(w http.ResponseWriter, r *http.Request) {
  var cars []Car

  db.Find(&cars)
  json.NewEncoder(w).Encode(&cars)
}

func GetCar(w http.ResponseWriter, r *http.Request) {
  params := mux.Vars(r)
  var car Car

  db.First(&car, params["id"])
  json.NewEncoder(w).Encode(&car)
}

func GetDriver(w http.ResponseWriter, r *http.Request) {
  params := mux.Vars(r)
  var driver Driver
  var cars   []Car

  db.First(&driver, params["id"])
  db.Model(&driver).Related(&cars)
  driver.Cars = cars
  json.NewEncoder(w).Encode(&driver)
}

func DeleteCar(w http.ResponseWriter, r *http.Request) {
  params := mux.Vars(r)
  var car Car

  db.First(&car, params["id"])
  db.Delete(&car)

  var cars []Car

  db.Find(&cars)
  json.NewEncoder(w).Encode(&cars)
}

运行测试

现在,您应该在一个文件中包含了运行所需的所有代码,您基本上已经有了一个模型-视图-控制器,来管理您的汽车和驾驶员。让我们试一试吧!在您的终端中,调用 “go run gorm_demo.go”。这将启动一个 Web 服务器,该服务器监听指定的端口(在我们的示例中为 “:8080”)。您现在需要打开浏览器,并导航到 “localhost:8080”,或者简单地使用 “curl” 来加载页面(因为我们从未真正定义过任何 HTML 模板):

$ curl localhost:8080/cars
[{"ID":1,"CreatedAt":"2019-12-20T23:38:26.176961Z","UpdatedAt":"2019-12-20T23:38:26.176961Z","DeletedAt":null,"Year":2000,"Make":"Toyota","ModelName":"Tundra","DriverID":1},
{"ID":2,"CreatedAt":"2019-12-20T23:38:26.178927Z","UpdatedAt":"2019-12-20T23:38:26.178927Z","DeletedAt":null,"Year":2001,"Make":"Honda","ModelName":"Accord","DriverID":1},
{"ID":3,"CreatedAt":"2019-12-20T23:38:26.179947Z","UpdatedAt":"2019-12-20T23:38:26.179947Z","DeletedAt":null,"Year":2002,"Make":"Nissan","ModelName":"Sentra","DriverID":2},
{"ID":4,"CreatedAt":"2019-12-20T23:38:26.180939Z","UpdatedAt":"2019-12-20T23:38:26.180939Z","DeletedAt":null,"Year":2003,"Make":"Ford","ModelName":"F-150","DriverID":3}]

请注意,JSON 是未格式化的。如果你想漂亮地打印它(无需重构 Go 代码),最简单的方法是,将其用管道输出到 “python -m json.tool”。为了篇幅原因,此处只在最后一个示例中使用了该方法。

由于我们基本上创建了一个 REST API,因此我们可以用 ID 来检索 Car:

$ curl localhost:8080/cars/2
{"ID":2,"CreatedAt":"2019-12-20T23:38:26.178927Z","UpdatedAt":"2019-12-20T23:38:26.178927Z","DeletedAt":null,"Year":2001,"Make":"Honda","ModelName":"Accord","DriverID":1}

我们还可以删除 Car:

$ curl -X DELETE localhost:8080/cars/2
[{"ID":1,"CreatedAt":"2019-12-20T23:38:26.176961Z","UpdatedAt":"2019-12-20T23:38:26.176961Z","DeletedAt":null,"Year":2000,"Make":"Toyota","ModelName":"Tundra","DriverID":1},
{"ID":3,"CreatedAt":"2019-12-20T23:38:26.179947Z","UpdatedAt":"2019-12-20T23:38:26.179947Z","DeletedAt":null,"Year":2002,"Make":"Nissan","ModelName":"Sentra","DriverID":2},
{"ID":4,"CreatedAt":"2019-12-20T23:38:26.180939Z","UpdatedAt":"2019-12-20T23:38:26.180939Z","DeletedAt":null,"Year":2003,"Make":"Ford","ModelName":"F-150","DriverID":3}]

最后,如果你还记得,我们在 Driver 和 Car 之间定义了一对多的关系,所以如果我们获取一个 Driver,我们可以看到和它相关的 Car(并且用 python 的 “json.tool” 模块,对输出进行美化):

$ curl localhost:8080/drivers/1 | python -m json.tool
{
    "ID": 1,
    "CreatedAt": "2019-12-20T23:38:26.181909Z",
    "UpdatedAt": "2019-12-20T23:38:26.181909Z",
    "DeletedAt": null,
    "Name": "Jimmy Johnson",
    "License": "ABC123",

    "Cars": [
        {
            "ID": 1,
            "CreatedAt": "2019-12-20T23:38:26.176961Z",
            "UpdatedAt": "2019-12-20T23:38:26.176961Z",
            "DeletedAt": null,
            "Year": 2000,
            "Make": "Toyota",
            "ModelName": "Tundra",
            "DriverID": 1
        }
    ]
}

运行结果不错!一个简单而有效的示例,说明了如何将 PostgreSQL 与 Go 的 ORM 一起使用。有关 GORM 功能的更多信息,您可能需要查看他们的文档