有些软件工程师选择使用 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 功能的更多信息,您可能需要查看他们的文档。