Go 使用 SQL 和 NoSQL 数据库详解

在本章中,我们将介绍以下配方:

每当我们想要持久化数据时,我们总是希望将其保存在数据库中,数据库主要分为两类:SQLNoSQL。根据业务用例的不同,每个类别下都有许多数据库可供使用,因为每个数据库都有不同的特性和用途。

在本章中,我们将把一个 Go web 应用与最著名的开源数据库MySQLMongoDB进行集成,并学习对它们执行 CRUD 操作。由于我们将使用 MySQL 和 MongoDB,我假设这两个数据库都已安装并运行在您的本地机器上。

假设您是一名开发人员,希望将应用数据保存在 MySQL 数据库中。作为第一步,您必须在应用和 MySQL 之间建立连接,我们将在本配方中介绍这一点

通过执行以下命令,验证 MySQL 是否在端口3306上本地安装和运行:

$ ps -ef | grep 3306

这将返回以下响应:

另外,登录 MySQL 数据库并创建一个 mydb 数据库,执行如下屏幕截图所示的命令:

  1. 使用go get命令安装github.com/go-sql-driver/mysql包,如下所示:
$ go get github.com/go-sql-driver/mysql
  1. 创建connect-mysql.go。然后我们连接到 MySQL 数据库,进行SELECT查询,得到当前的数据库名称,如下所示:
package main
import 
(
  "database/sql"
  "fmt"
  "log"
  "net/http"
  "github.com/go-sql-driver/mysql"
)
const 
(
  CONN_HOST = "localhost"
  CONN_PORT = "8080"
  DRIVER_NAME = "mysql"
  DATA_SOURCE_NAME = "root:password@/mydb"
)
var db *sql.DB
var connectionError error
func init() 
{
  db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
  if connectionError != nil 
  {
    log.Fatal("error connecting to database :: ", connectionError)
  }
}
func getCurrentDb(w http.ResponseWriter, r *http.Request) 
{
  rows, err := db.Query("SELECT DATABASE() as db")
  if err != nil 
  {
    log.Print("error executing query :: ", err)
    return
  }
  var db string
  for rows.Next() 
  {
    rows.Scan(&db)
  }
  fmt.Fprintf(w, "Current Database is :: %s", db)
}
func main() 
{
  http.HandleFunc("/", getCurrentDb)
  defer db.Close()
  err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
  if err != nil 
  {
    log.Fatal("error starting http server :: ", err)
    return
  }
}
  1. 使用以下命令运行程序:
$ go run connect-mysql.go

一旦我们运行程序,HTTP 服务器将在端口8080上开始本地侦听

浏览http://localhost:8080/会返回当前数据库名称,如下图所示:

让我们了解一下我们编写的程序:

  1. 我们使用import ( "database/sql" "fmt" "log" "net/http" _ "github.com/go-sql-driver/mysql")导入github.com/go-sql-driver/mysql是因为它的副作用或初始化,在 import 语句前面显式使用下划线。

  2. 使用var db *sql.DB,我们声明了一个私有DB实例。

根据项目大小,您可以全局声明 DB 实例,使用处理程序将其作为依赖项注入,或者将连接池指针放入x/net/context

  1. 接下来,我们定义了一个init()函数,在该函数中,我们连接到数据库,并向其传递数据库驱动程序名称和数据源。
  2. 然后,我们定义了一个getCurrentDb处理程序,它基本上对数据库执行一个 select 查询,以获取当前数据库名称,迭代记录,将其值复制到变量中,并最终将其写入 HTTP 响应流。

在数据库中创建或保存记录需要我们编写 SQL 查询并执行它们,实现对象关系映射ORM),或者实现数据映射技术。

在这个配方中,我们将编写一个 SQL 查询,并使用database/sql包执行它来创建一个记录。为了实现这一点,您还可以使用 Go 中提供的许多第三方库中的任何库来实现 ORM,例如https://github.com/jinzhu/gormhttps://github.com/go-gorp/gorphttps://github.com/jirfag/go-queryset

由于我们在前面的配方中已经与 MySQL 数据库建立了连接,因此我们将扩展它以创建一个执行 SQL 查询的记录。

在创建记录之前,我们必须在 MySQL 数据库中创建一个表,我们将通过执行以下屏幕截图中所示的命令来实现这一点:

  1. 使用go get命令安装github.com/go-sql-driver/mysqlgithub.com/gorilla/mux包,如下所示:
$ go get github.com/go-sql-driver/mysql
$ go get github.com/gorilla/mux
  1. 创建create-record-mysql.go,然后连接 MySQL 数据库,进行插入查询,创建员工记录,如下图:
package main
import 
(
  "database/sql"
  "fmt"
  "log"
  "net/http"
  "strconv"
  "github.com/go-sql-driver/mysql"
  "github.com/gorilla/mux"
)
const 
(
  CONN_HOST = "localhost"
  CONN_PORT = "8080"
  DRIVER_NAME = "mysql"
  DATA_SOURCE_NAME = "root:password@/mydb"
)
var db *sql.DB
var connectionError error
func init() 
{
  db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
  if connectionError != nil 
  {
    log.Fatal("error connecting to database : ", connectionError)
  }
}
func createRecord(w http.ResponseWriter, r *http.Request) 
{
  vals := r.URL.Query()
  name, ok := vals["name"]
  if ok 
  {
    log.Print("going to insert record in database for name : ",
    name[0])
    stmt, err := db.Prepare("INSERT employee SET name=?")
    if err != nil 
    {
      log.Print("error preparing query :: ", err)
      return
    }
    result, err := stmt.Exec(name[0])
    if err != nil 
    {
      log.Print("error executing query :: ", err)
      return
    }
    id, err := result.LastInsertId()
    fmt.Fprintf(w, "Last Inserted Record Id is :: %s",
    strconv.FormatInt(id, 10))
  } 
  else 
  {
    fmt.Fprintf(w, "Error occurred while creating record in 
    database for name :: %s", name[0])
  }
}
func main() 
{
  router := mux.NewRouter()
  router.HandleFunc("/employee/create", createRecord).
  Methods("POST")
  defer db.Close()
  err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
  if err != nil 
  {
    log.Fatal("error starting http server : ", err)
    return
  }
}
  1. 使用以下命令运行程序:
$ go run create-record-mysql.go

一旦我们运行程序,HTTP 服务器将在端口8080上开始本地侦听

从命令行执行POST请求以创建员工记录,如下所示,将为您提供上次创建的记录的 ID:

$ curl -X POST http://localhost:8080/employee/create?name=foo
Last created record id is :: 1

让我们了解一下我们编写的程序:

  1. 使用import ("database/sql" "fmt" "log" "net/http" "strconv" _ "github.com/go-sql-driver/mysql" "github.com/gorilla/mux")导入github.com/gorilla/mux创建 Gorilla Mux 路由器,初始化 Go MySQL 驱动,导入github.com/go-sql-driver/mysql包。
  2. 接下来,我们定义了一个createRecord处理程序,它从请求中获取名称,将其分配给局部变量名称,准备一个带有名称占位符的INSERT语句,该占位符将动态替换为名称,执行该语句,并最终将最后创建的 ID 写入 HTTP 响应流。

在前面的方法中,我们在 MySQL 数据库中创建了一个雇员记录。现在,在这个配方中,我们将学习如何通过执行 SQL 查询来读取它。

  1. 使用go get命令安装github.com/go-sql-driver/mysqlgithub.com/gorilla/mux包,如下所示:
$ go get github.com/go-sql-driver/mysql
$ go get github.com/gorilla/mux
  1. 创建read-record-mysql.go连接到 MySQL 数据库,执行SELECT查询,从数据库中获取所有员工,遍历记录,将其值复制到 struct 中,将所有员工添加到列表中,并将其写入 HTTP 响应流,如下所示:
package main
import 
(
  "database/sql" "encoding/json"
  "log"
  "net/http"
  "github.com/go-sql-driver/mysql"
  "github.com/gorilla/mux"
)
const 
(
  CONN_HOST = "localhost"
  CONN_PORT = "8080"
  DRIVER_NAME = "mysql"
  DATA_SOURCE_NAME = "root:password@/mydb"
)
var db *sql.DB
var connectionError error
func init() 
{
  db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
  if connectionError != nil 
  {
    log.Fatal("error connecting to database :: ", connectionError)
  }
}
type Employee struct 
{
  Id int `json:"uid"`
  Name string `json:"name"`
}
func readRecords(w http.ResponseWriter, r *http.Request) 
{
  log.Print("reading records from database")
  rows, err := db.Query("SELECT * FROM employee")
  if err != nil 
  {
    log.Print("error occurred while executing select 
    query :: ",err)
    return
  }
  employees := []Employee{}
  for rows.Next() 
  {
    var uid int
    var name string
    err = rows.Scan(&uid, &name)
    employee := Employee{Id: uid, Name: name}
    employees = append(employees, employee)
  }
  json.NewEncoder(w).Encode(employees)
}
func main() 
{
  router := mux.NewRouter()
  router.HandleFunc("/employees", readRecords).Methods("GET")
  defer db.Close()
  err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
  if err != nil 
  {
    log.Fatal("error starting http server :: ", err)
    return
  }
}
  1. 使用以下命令运行程序:
$ go run read-record-mysql.go

一旦我们运行程序,HTTP 服务器将在端口8080上开始本地侦听。

浏览http://localhost:8080/employees将列出员工表中的所有记录,如下图所示:

让我们看看我们编写的程序:

  1. 使用import ( "database/sql" "encoding/json" "log" "net/http" _ "github.com/go-sql-driver/mysql" "github.com/gorilla/mux"),我们导入了一个额外的包encoding/json,它有助于将 Go 数据结构编组到JSON
  2. 接下来,我们声明了 Go 数据结构Person,它有IdName字段。

请记住,字段名在类型定义中应以大写字母开头,否则可能会出现错误

  1. 接下来,我们定义了一个readRecords处理程序,它查询数据库以从 employee 表中获取所有记录,迭代记录,将其值复制到结构中,将所有记录添加到列表中,将对象列表封送到 JSON,并将其写入 HTTP 响应流。

考虑一个场景,您为数据库中的雇员创建了一个记录,记录有所有的细节,如名称、部门、地址等,并且在一段时间之后,雇员更改部门。在这种情况下,我们必须在数据库中更新他们的部门,以便他们的详细信息在整个组织内同步,这可以通过使用SQL UPDATE语句实现,在本配方中,我们将了解如何在 Go 中实现它。

  1. 使用go get命令安装github.com/go-sql-driver/mysqlgithub.com/gorilla/mux包,如下所示:
$ go get github.com/go-sql-driver/mysql
$ go get github.com/gorilla/mux
  1. 创建update-record-mysql.go。然后我们连接到 MySQL 数据库,更新员工的姓名作为 ID,并将数据库中更新的记录数写入 HTTP 响应流,如下所示:
package main
import 
(
  "database/sql"
  "fmt"
  "log"
  "net/http" 
  "github.com/go-sql-driver/mysql"
  "github.com/gorilla/mux"
)
const 
(
  CONN_HOST = "localhost"
  CONN_PORT = "8080"
  DRIVER_NAME = "mysql"
  DATA_SOURCE_NAME = "root:password@/mydb"
)
var db *sql.DB
var connectionError error 
func init() 
{
  db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
  if connectionError != nil 
  {
    log.Fatal("error connecting to database :: ", connectionError)
  }
}
type Employee struct 
{
  Id   int    `json:"uid"`
  Name string `json:"name"`
}
func updateRecord(w http.ResponseWriter, r *http.Request) 
{
  vars := mux.Vars(r)
  id := vars["id"]
  vals := r.URL.Query()
  name, ok := vals["name"]
  if ok 
  {
    log.Print("going to update record in database 
    for id :: ", id)
    stmt, err := db.Prepare("UPDATE employee SET name=? 
    where uid=?")
    if err != nil 
    {
      log.Print("error occurred while preparing query :: ", err)
      return
    }
    result, err := stmt.Exec(name[0], id)
    if err != nil 
    {
      log.Print("error occurred while executing query :: ", err)
      return
    }
    rowsAffected, err := result.RowsAffected()
    fmt.Fprintf(w, "Number of rows updated in database 
    are :: %d",rowsAffected)
  } 
  else 
  {
    fmt.Fprintf(w, "Error occurred while updating record in 
    database for id :: %s", id)
  }
}
func main() 
{
  router := mux.NewRouter()
  router.HandleFunc("/employee/update/{id}",
  updateRecord).Methods("PUT")
  defer db.Close()
  err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
  if err != nil 
  {
    log.Fatal("error starting http server :: ", err)
    return
  }
}
  1. 使用以下命令运行程序:
$ go run update-record-mysql.go

一旦我们运行程序,HTTP 服务器将在端口8080上开始本地侦听

接下来,从命令行执行一个PUT请求,以更新 ID 为1的员工记录,将给出数据库中更新的记录数作为响应:

$ curl -X PUT http://localhost:8080/employee/update/1?name\=bar
Number of rows updated in database are :: 1

让我们看看我们编写的程序:

  1. 我们定义了一个updateRecord处理程序,该处理程序将数据库中要更新的 ID 作为 URL 路径变量 path,将新名称作为请求变量,准备一个update语句,其中名称和 UID 作为占位符,将动态替换该语句,执行该语句,获取执行后更新的行数,并将其写入 HTTP 响应流。
  2. 接下来,我们向gorilla/mux路由器注册了一个updateRecord处理程序,为每个PUT请求调用 URL 模式/employee/update/{id},并在我们从main()函数返回后使用defer db.Close()语句关闭数据库。

考虑一个雇员离开组织的情况,您想从数据库中撤消他们的详细信息。在这种情况下,我们可以使用SQL DELETE语句,我们将在本配方中介绍它。

  1. 使用go get命令安装github.com/go-sql-driver/mysqlgithub.com/gorilla/mux包,如下所示:
$ go get github.com/go-sql-driver/mysql
$ go get github.com/gorilla/mux
  1. 创建delete-record-mysql.go。然后我们连接到 MySQL 数据库,从数据库中删除一名员工的姓名,并将从数据库中删除的记录数写入 HTTP 响应流,如下所示:
package main
import 
(
  "database/sql"
  "fmt"
  "log"
  "net/http"
  "github.com/go-sql-driver/mysql"
  "github.com/gorilla/mux"
)
const 
(
  CONN_HOST = "localhost"
  CONN_PORT = "8080"
  DRIVER_NAME = "mysql"
  DATA_SOURCE_NAME = "root:password@/mydb"
)
var db *sql.DB
var connectionError error
func init() 
{
  db, connectionError = sql.Open(DRIVER_NAME, DATA_SOURCE_NAME)
  if connectionError != nil 
  {
    log.Fatal("error connecting to database :: ", connectionError)
  }
}
func deleteRecord(w http.ResponseWriter, r *http.Request) 
{
  vals := r.URL.Query()
  name, ok := vals["name"]
  if ok 
  {
    log.Print("going to delete record in database for 
    name :: ", name[0])
    stmt, err := db.Prepare("DELETE from employee where name=?")
    if err != nil 
    {
      log.Print("error occurred while preparing query :: ", err)
      return
    }
    result, err := stmt.Exec(name[0])
    if err != nil 
    {
      log.Print("error occurred while executing query :: ", err)
      return
    }
    rowsAffected, err := result.RowsAffected()
    fmt.Fprintf(w, "Number of rows deleted in database are :: %d",
    rowsAffected)
  } 
  else 
  {
    fmt.Fprintf(w, "Error occurred while deleting record in 
    database for name %s", name[0])
  }
}
func main() 
{
  router := mux.NewRouter()
  router.HandleFunc("/employee/delete",
  deleteRecord).Methods("DELETE")
  defer db.Close()
  err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
  if err != nil 
  {
    log.Fatal("error starting http server :: ", err)
    return
  }
}
  1. 使用以下命令运行程序:
$ go run delete-record-mysql.go

一旦我们运行程序,HTTP 服务器将在端口8080上开始本地侦听

接下来,从命令行执行一个DELETE请求,删除一个名为bar的员工,将得到从数据库中删除的记录数:

$ curl -X DELETE http://localhost:8080/employee/delete?name\=bar
Number of rows deleted in database are :: 1

让我们看看我们编写的程序:

  1. 我们定义了一个deleteRecord处理程序,它获取要从数据库中删除的名称作为请求变量,准备一个DELETE语句,该语句的名称作为占位符,将被动态替换,执行该语句,获取执行后删除的行数,并将其写入 HTTP 响应流。
  2. 接下来,我们向gorilla/mux路由器注册了一个deleteRecord处理程序,为每个DELETE请求调用 URL 模式/employee/delete,并在main()函数返回后使用defer db.Close()语句关闭数据库。

每当您想要在 MongoDB 数据库中持久化数据时,您必须采取的第一步是在数据库和您的 web 应用之间建立连接,我们将在本食谱中使用 Go-gopkg.in/mgo.v2最著名和最常用的 MongoDB 驱动程序之一来介绍这一点。

通过执行以下命令,验证MongoDB是否已安装并在端口27017上本地运行:

$ mongo

这将返回以下响应:

  1. 使用go get命令安装gopkg.in/mgo.v包,如下所示:
$ go get gopkg.in/mgo.v
  1. 创建connect-mongodb.go。然后我们连接到MongoDB数据库,从集群中获取所有数据库名称,并将它们写入 HTTP 响应流,如下所示:
package main
import 
(
  "fmt"
  "log"
  "net/http"
  "strings"
  mgo "gopkg.in/mgo.v2"
)
const 
(
  CONN_HOST = "localhost"
  CONN_PORT = "8080"
  MONGO_DB_URL = "127.0.0.1"
)
var session *mgo.Session
var connectionError error
func init() 
{
  session, connectionError = mgo.Dial(MONGO_DB_URL)
  if connectionError != nil 
  {
    log.Fatal("error connecting to database :: ", connectionError)
  }
  session.SetMode(mgo.Monotonic, true)
}
func getDbNames(w http.ResponseWriter, r *http.Request) 
{
  db, err := session.DatabaseNames()
  if err != nil 
  {
    log.Print("error getting database names :: ", err)
    return
  }
  fmt.Fprintf(w, "Databases names are :: %s", strings.Join
  (db, ", "))
}
func main() 
{
  http.HandleFunc("/", getDbNames)
  defer session.Close()
  err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, nil)
  if err != nil 
  {
    log.Fatal("error starting http server :: ", err)
    return
  }
}
  1. 使用以下命令运行程序:
$ go run connect-mongodb.go

一旦我们运行程序,HTTP 服务器将在端口8080上开始本地侦听

浏览到http://localhost:8080/将列出 MongoDB 集群中存在的所有数据库的名称,如下图所示:

让我们看看我们编写的程序:

  1. 我们使用import ( "fmt" "log" "net/http" "strings" mgo "gopkg.in/mgo.v2" )导入gopkg.in/mgo.v2,包别名为mgo
  2. 我们使用var session *mgo.Session声明私有 MongoDBSession实例,该实例充当与数据库的通信会话。
  3. 使用var connectionError error,我们声明了一个私有error对象。
  4. 接下来,我们定义了init()函数,其中我们连接到 MongoDB,将主机传递为127.0.0.1,这意味着 MongoDB 和应用都在端口27017的同一台机器上运行,可以选择将会话切换为单调行为,以便读取的数据在同一会话中的顺序查询中保持一致,在会话中所做的修改将在随后的查询中观察到。

如果您的 MongoDB 运行在除27017之外的端口上,那么您必须传递主机和端口,以冒号分隔,如:mgo.Dial("localhost:27018")

  1. 接下来,我们定义了一个getDbNames处理程序,它基本上从 MongoDB 集群获取所有数据库名称,并将它们作为逗号分隔的字符串写入 HTTP 响应流。

在本教程中,我们将学习如何使用 Go 的 MongoDB 驱动程序(gopkg.In/mgo.v2)在数据库中创建 BSON 文档(类似 JSON 文档的二进制编码序列化)

  1. 使用go get命令安装gopkg.in/mgo.v2github.com/gorilla/mux包,如下所示:
$ go get gopkg.in/mgo.v2
$ go get github.com/gorilla/mux
  1. 创建create-record-mongodb.go。然后我们连接到 MongoDB 数据库,创建一个带有两个字段 ID 和 name 的 employee 文档,并将上次创建的文档 ID 写入 HTTP 响应流,如下所示:
package main
import 
(
  "fmt"
  "log"
  "net/http"
  "strconv"
  "github.com/gorilla/mux"
  mgo "gopkg.in/mgo.v2"
)
const 
(
  CONN_HOST = "localhost"
  CONN_PORT = "8080"
  MONGO_DB_URL = "127.0.0.1"
)
var session *mgo.Session
var connectionError error
type Employee struct 
{
  Id int `json:"uid"`
  Name string `json:"name"`
}
func init() 
{
  session, connectionError = mgo.Dial(MONGO_DB_URL)
  if connectionError != nil 
  {
    log.Fatal("error connecting to database :: ", connectionError)
  }
  session.SetMode(mgo.Monotonic, true)
}
func createDocument(w http.ResponseWriter, r *http.Request) 
{
  vals := r.URL.Query()
  name, nameOk := vals["name"]
  id, idOk := vals["id"]
  if nameOk && idOk 
  {
    employeeId, err := strconv.Atoi(id[0])
    if err != nil 
    {
      log.Print("error converting string id to int :: ", err)
      return
    }
    log.Print("going to insert document in database for name 
    :: ", name[0])
    collection := session.DB("mydb").C("employee")
    err = collection.Insert(&Employee{employeeId, name[0]})
    if err != nil 
    {
      log.Print("error occurred while inserting document in 
      database :: ", err)
      return
    }
    fmt.Fprintf(w, "Last created document id is :: %s", id[0])
  } 
  else 
  {
    fmt.Fprintf(w, "Error occurred while creating document in
    database for name :: %s", name[0])
  }
}
func main() 
{
  router := mux.NewRouter()
  router.HandleFunc("/employee/create",
  createDocument).Methods("POST")
  defer session.Close()
  err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
  if err != nil 
  {
    log.Fatal("error starting http server :: ", err)
    return
  }
}
  1. 使用以下命令运行程序:
$ go run create-record-mongodb.go

一旦我们运行程序,HTTP 服务器将在端口8080上开始本地侦听

接下来,从命令行执行POST请求以创建员工文档,如下所示,将为您提供在 MongoDB 中创建的文档的 ID:

$ curl -X POST http://localhost:8080/employee/create?name=foo\&id=1
Last created document id is :: 1

让我们看看我们编写的程序:

  1. 我们使用import ( "fmt" "log" "net/http" "strconv" "github.com/gorilla/mux" mgo "gopkg.in/mgo.v2")导入github.com/gorilla/mux创建 Gorilla Mux 路由器和gopkg.in/mgo.v2,包别名为mgo,作为 MongoDB 驱动。
  2. 接下来,我们定义了一个createDocument处理程序,它从 HTTP 请求中获取员工的姓名和 ID。因为请求变量的类型为string,所以我们将string类型的变量 ID 转换为int类型。然后,我们从 MongoDB 获取 employee 集合并调用collection.Insert处理程序在数据库中保存Employee结构类型的实例。

在前面的配方中,我们在 MongoDB 中创建了一个 BSON 文档。现在,在这个配方中,我们将学习如何使用gopkg.in/mgo.v2/bson包来阅读它,它有助于查询 MongoDB 集合。

  1. 使用go get命令安装gopkg.in/mgo.v2gopkg.in/mgo.v2/bsongithub.com/gorilla/mux包,如下所示:
$ go get gopkg.in/mgo.v2
$ go get gopkg.in/mgo.v2/bson
$ go get github.com/gorilla/mux
  1. 创建read-record-mongodb.go。然后我们连接到 MongoDB 数据库,读取员工集合中的所有文档,将列表封送到 JSON,并将其写入 HTTP 响应流,如下所示:
package main
import 
(
  "encoding/json"
  "log"
  "net/http"
  "github.com/gorilla/mux"
  mgo "gopkg.in/mgo.v2"
  "gopkg.in/mgo.v2/bson"
)
const 
(
  CONN_HOST = "localhost"
  CONN_PORT = "8080"
  MONGO_DB_URL = "127.0.0.1"
)
var session *mgo.Session
var connectionError error
func init() 
{
  session, connectionError = mgo.Dial(MONGO_DB_URL)
  if connectionError != nil 
  {
    log.Fatal("error connecting to database :: ", connectionError)
  }
  session.SetMode(mgo.Monotonic, true)
}
type Employee struct 
{
  Id int `json:"uid"`
  Name string `json:"name"`
}
func readDocuments(w http.ResponseWriter, r *http.Request) 
{
  log.Print("reading documents from database")
  var employees []Employee
  collection := session.DB("mydb").C("employee")
  err := collection.Find(bson.M{}).All(&employees)
  if err != nil 
  {
    log.Print("error occurred while reading documents from 
    database :: ", err)
    return
  }
  json.NewEncoder(w).Encode(employees)
}
func main() 
{
  router := mux.NewRouter()
  router.HandleFunc("/employees", readDocuments).Methods("GET")
  defer session.Close()
  err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
  if err != nil 
  {
    log.Fatal("error starting http server :: ", err)
    return
  }
}
  1. 使用以下命令运行程序:
$ go run read-record-mongodb.go

一旦我们运行程序,HTTP 服务器将在端口8080上开始本地侦听。

接下来,浏览到http://localhost:8080/employees将为您提供 MongoDB 员工集合中所有员工的列表:

让我们看看我们在计划中引入的变化:

  1. 使用import ( "encoding/json" "log" "net/http" "github.com/gorilla/mux" mgo "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson"),我们导入了一个额外的gopkg.in/mgo.v2/bson包,它是 Go 的 BSON 规范,以及encoding/json包,我们用于将从 MongoDB 获得的对象列表封送到JSON
  2. 接下来,我们定义了一个readDocuments处理程序,首先从 MongoDB 获取 employee 集合,查询其中的所有文档,迭代文档以将其映射到Employee结构的数组,最后将其封送到JSON

一旦创建了 BSON 文档,我们可能需要更新它的一些字段。在这种情况下,我们必须对 MongoDB 集合执行update/upsert查询,我们将在本配方中介绍。

  1. 使用go get命令安装gopkg.in/mgo.v2gopkg.in/mgo.v2/bsongithub.com/gorilla/mux包,如下所示:
$ go get gopkg.in/mgo.v2
$ go get gopkg.in/mgo.v2/bson
$ go get github.com/gorilla/mux
  1. 创建update-record-mongodb.go。然后我们连接到 MongoDB 数据库,更新员工的姓名以获取 ID,并将 MongoDB 中更新的记录数写入 HTTP 响应流,如下所示:
package main
import 
(
  "fmt"
  "log"
  "net/http"
  "strconv"
  "github.com/gorilla/mux"
  mgo "gopkg.in/mgo.v2"
  "gopkg.in/mgo.v2/bson"
)
const 
(
  CONN_HOST = "localhost"
  CONN_PORT = "8080"
  MONGO_DB_URL = "127.0.0.1"
)
var session *mgo.Session
var connectionError error
type Employee struct 
{
  Id int `json:"uid"`
  Name string `json:"name"`
}
func init() 
{
  session, connectionError = mgo.Dial(MONGO_DB_URL)
  if connectionError != nil 
  {
    log.Fatal("error connecting to database :: ", 
    connectionError)
  }
  session.SetMode(mgo.Monotonic, true)
}
func updateDocument(w http.ResponseWriter, r *http.Request) 
{
  vars := mux.Vars(r)
  id := vars["id"]
  vals := r.URL.Query()
  name, ok := vals["name"]
  if ok 
  {
    employeeId, err := strconv.Atoi(id)
    if err != nil 
    {
      log.Print("error converting string id to int :: ", err)
      return
    }
    log.Print("going to update document in database 
    for id :: ", id)
    collection := session.DB("mydb").C("employee")
    var changeInfo *mgo.ChangeInfo
    changeInfo, err = collection.Upsert(bson.M{"id": employeeId},
    &Employee{employeeId, name[0]})
    if err != nil 
    {
      log.Print("error occurred while updating record in 
      database :: ", err)
      return
    }
    fmt.Fprintf(w, "Number of documents updated in database 
    are :: %d", changeInfo.Updated)
  } 
  else 
  {
    fmt.Fprintf(w, "Error occurred while updating document
    in database for id :: %s", id)
  }
}
func main() 
{
  router := mux.NewRouter()
  router.HandleFunc("/employee/update/{id}",
  updateDocument).Methods("PUT")
  defer session.Close()
  err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
  if err != nil 
  {
    log.Fatal("error starting http server :: ", err)
    return
  }
}
  1. 使用以下命令运行程序:
$ go run update-record-mongodb.go

一旦我们运行程序,HTTP 服务器将在端口8080上开始本地侦听

接下来,从命令行执行对UPDATE员工文档的PUT请求,如下所示,将为您提供 MongoDB 中更新的文档数量:

$ curl -X PUT http://localhost:8080/employee/update/1\?name\=bar
Number of documents updated in database are :: 1

让我们看看我们编写的程序:

  1. 我们定义了一个updateDocument处理程序,它将在 MongoDB 中更新的 ID 作为 URL 路径变量,将新名称作为 HTTP 请求变量。由于请求变量是字符串类型,我们已经将变量 IDstring类型转换为int类型。然后,我们从 MongoDB 获取 employee 集合,如果不存在,则调用collection.Upsert处理程序进行插入,或者使用所提供 ID 的新名称更新员工文档。
  2. 接下来,我们注册了一个updateDocument处理程序,在gorilla/mux路由器上为每个PUT请求调用 URL 模式/employee/update/{id},并在从main()函数返回后使用defer session.Close()语句关闭 MongoDB 会话。

每当我们想要清理数据库或删除不再需要的文档时,我们都可以使用 MongoDB gopkg 驱动程序(gopkg.in/mgo.v2)轻松删除它们,我们将在本配方中介绍这一点。

  1. 使用go get命令安装gopkg.in/mgo.v2gopkg.in/mgo.v2/bsongithub.com/gorilla/mux包,如下所示:
$ go get gopkg.in/mgo.v2
$ go get gopkg.in/mgo.v2/bson
$ go get github.com/gorilla/mux
  1. 创建delete-record-mongodb.go。然后我们连接到 MongoDB,获取要从数据库中删除的员工的姓名作为 HTTP 请求变量,获取命名集合,然后删除文档,如下所示:
package main
import 
(
  "fmt"
  "log"
  "net/http"
  "github.com/gorilla/mux"
  mgo "gopkg.in/mgo.v2"
  "gopkg.in/mgo.v2/bson"
)
const 
(
  CONN_HOST = "localhost"
  CONN_PORT = "8080"
  MONGO_DB_URL = "127.0.0.1"
)
var session *mgo.Session
var connectionError error
type Employee struct 
{
  Id int `json:"uid"`
  Name string `json:"name"`
}
func init() 
{
  session, connectionError = mgo.Dial(MONGO_DB_URL)
  if connectionError != nil 
  {
    log.Fatal("error connecting to database :: ", 
    connectionError)
  }
  session.SetMode(mgo.Monotonic, true)
}
func deleteDocument(w http.ResponseWriter, r *http.Request) 
{
  vals := r.URL.Query()
  name, ok := vals["name"]
  if ok 
  {
    log.Print("going to delete document in database for 
    name :: ", name[0])
    collection := session.DB("mydb").C("employee")
    removeErr := collection.Remove(bson.M{"name": name[0]})
    if removeErr != nil 
    {
      log.Print("error removing document from 
      database :: ", removeErr)
      return
    }
    fmt.Fprintf(w, "Document with name %s is deleted from 
    database", name[0])
  } 
  else 
  {
    fmt.Fprintf(w, "Error occurred while deleting document 
    in database for name :: %s", name[0])
  }
}
func main() 
{
  router := mux.NewRouter()
  router.HandleFunc("/employee/delete",
  deleteDocument).Methods("DELETE")
  defer session.Close()
  err := http.ListenAndServe(CONN_HOST+":"+CONN_PORT, router)
  if err != nil 
  {
    log.Fatal("error starting http server :: ", err)
    return
  }
}
  1. 使用以下命令运行程序:
$ go run delete-record-mongodb.go

一旦我们运行程序,HTTP 服务器将在端口8080上开始本地侦听

接下来,执行从命令行删除 BSON 文档的DELETE请求,如下所示,将为您提供从数据库中删除的文档的名称:

$ curl -X DELETE http://localhost:8080/employee/delete?name\=bar
Document with name bar is deleted from database

让我们看看我们编写的程序:

  1. 我们定义了一个deleteDocument处理程序,该处理程序从 MongoDB 获取要删除的名称作为请求变量,从 MongoDB 获取 employee 集合,并调用collection.Remove处理程序删除给定名称的文档。
  2. 然后,我们注册了一个deleteDocument处理程序,在gorilla/mux路由器上为每个DELETE请求调用 URL 模式/employee/delete,并在main()函数返回后使用defer session.Close()语句关闭 MongoDB 会话。

教程来源于Github,感谢apachecn大佬的无私奉献,致敬!

技术教程推荐

从0开始学架构 -〔李运华〕

Java性能调优实战 -〔刘超〕

即时消息技术剖析与实战 -〔袁武林〕

DevOps实战笔记 -〔石雪峰〕

Netty源码剖析与实战 -〔傅健〕

基于人因的用户体验设计课 -〔刘石〕

Redis源码剖析与实战 -〔蒋德钧〕

深入浅出分布式技术原理 -〔陈现麟〕

Serverless进阶实战课 -〔静远〕