英文:
Golang pass arguments to gorilla router
问题
你可以在NewRouter
函数中创建数据库连接,并将其作为参数传递给每个处理程序函数。这样,所有处理程序函数都可以共享同一个数据库连接。
首先,在NewRouter
函数中创建数据库连接,并将其传递给每个处理程序函数。修改代码如下:
func NewRouter() *mux.Router {
db, err := sql.Open("mysql", "psanker:123@/education_data")
err = db.Ping()
if err != nil {
fmt.Println("Failed to prepare connection to database")
log.Fatal("Error:", err.Error())
}
defer db.Close()
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
// 将数据库连接作为参数传递给处理程序函数
route.HandlerFunc = withDB(route.HandlerFunc, db)
router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(route.HandlerFunc)
}
return router
}
然后,创建一个辅助函数withDB
,它接受处理程序函数和数据库连接作为参数,并返回一个新的处理程序函数,该函数在调用原始处理程序函数之前将数据库连接作为参数传递给它。修改代码如下:
func withDB(handler http.HandlerFunc, db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 在调用原始处理程序函数之前将数据库连接作为参数传递给它
handler(w, r, db)
}
}
最后,在每个处理程序函数中接受数据库连接作为参数,并使用它进行数据库操作。修改代码如下:
func getDistrict(w http.ResponseWriter, r *http.Request, db *sql.DB) {
vars := mux.Vars(r)
districtId := vars["districtId"]
fmt.Fprintln(w, "District id : ", districtId)
}
func getDistricts(w http.ResponseWriter, r *http.Request, db *sql.DB) {
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
w.WriteHeader(http.StatusOK)
rows, err := db.Query("SELECT * from districts")
check(err)
var district District
for rows.Next() {
var id int64
test := "hey"
district = District{Id: id, Activities: test}
}
if err := json.NewEncoder(w).Encode(district); err != nil {
check(err)
}
}
现在,每个处理程序函数都接受数据库连接作为参数,并可以使用它进行数据库操作。这样,它们将共享同一个数据库连接。
英文:
So I have two files. In one I have initialize a gorilla router, and register handlers. In the other I define the handlers. The handlers are supposed to query a MYSQL database. Routes.go looks like this -
package main
import (
"net/http"
"github.com/gorilla/mux"
"database/sql"
_ "github.com/go-sql-driver/mysql"
"fmt"
)
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
type Routes[]Route
func NewRouter() *mux.Router {
db, err := sql.Open("mysql", "psanker:123@/education_data")
err = db.Ping()
if err != nil {
fmt.Println("Failed to prepare connection to database")
log.Fatal("Error:", err.Error())
}
defer db.Close()
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(route.HandlerFunc)
}
return router
}
var routes = Routes{
Route {
"Index",
"GET",
"/",
Index,
},
Route {
"getDistrict",
"GET",
"/district/{districtId}",
getDistrict,
DBConn &db,
},
Route {
"getDistricts",
"GET",
"/districts",
getDistricts,
},
}
My handlers.go file looks like this -
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"encoding/json"
)
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "WELCOME!")
}
func getDistrict(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
districtId := vars["districtId"]
fmt.Fprintln(w, "District id : ", districtId)
}
func getDistricts(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
w.WriteHeader(http.StatusOK)
rows, err := db.Query("SELECT * from districts")
check(err)
var district District
for rows.Next() {
var id int64
test := "hey"
district = District{Id: id, Activities: test}
}
if err := json.NewEncoder(w).Encode(district); err != nil {
check(err)
}
}
I want to use one database connection for all of my handlers, how do I achieve this?
答案1
得分: 2
Go的sql.DB
类型表示一个连接池而不是单个连接。建议在程序初始化时创建一个连接池,并且可以选择以下两种方式:
- 创建一个全局连接池并直接使用它(连接池可以安全地进行并发访问)
var db *sql.DB
func main() {
var err error
db, err = sql.Open("connection string here")
if err != nil {
// 处理错误
}
// 程序的其他部分/路由器/等等
}
func MyHandler(w http.ResponseWriter, r *http.Request) {
err := db.Query("...")
if err != nil {
// 处理错误
}
// 处理程序的其他部分
}
- 创建满足
http.Handler
接口的自定义处理函数,并接受连接池或包含连接池的结构体作为额外参数。我在这里写了一篇文章介绍了这个方法:https://elithrar.github.io/article/custom-handlers-avoiding-globals/
(我可以提供另一个示例,但我现在在手机上,对不起排版可能不太好)
另外,可以查看sqlx来简化对结构体的查询和处理。
英文:
Go's sql.DB
type represents a connection pool and not a single connection. It is recommended that you create a pool on program initialization and either:
-
Create a global pool and just use it (the pool is safe for concurrent access)
var db *sql.DB func main() { var err error db, err = sql.Open("connection string here") if err != nil { // handle it } // Rest of program/router/etc } func MyHandler(w http.ResponseWriter, r *http.Request) { err := db.Query("...") if err != nil { // handle it } // Rest of handler }
-
Create custom handler functions that satisfy
http.Handler
and accept the pool or a struct containing the pool as an additional argument. I wrote about that here: https://elithrar.github.io/article/custom-handlers-avoiding-globals/
(I would provide another example but I'm on mobile; excuse the poor indentation)
Also look at sqlx to simplify your query into/from struct handling.
答案2
得分: 1
Elithar的回答是实现这一目标的标准方法。如果你想在每个处理程序中注入一个数据库连接,这是一种解决方法。你需要定义自己的处理程序,并将其转换回路由器所期望的形式。以下是Elithar可能想要给出的示例代码。
func main() {
http.HandlerFunc(myDbHandler(Index, db))
}
type dbHandler func(w http.ResponseWriter, r *http.Request, db *sql.DB)
func myDbHandler(handler dbHandler, db *sql.DB) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
handler(w, r, db)
}
}
func Index(w http.ResponseWriter, r *http.Request, db *sql.DB) {
// 处理程序的代码放在这里
}
希望对你有帮助!
英文:
Elithar's answer is the standard way of achieving this. If you want to inject a db connection in every handler, this is one way to solve it. You define your own handler and convert it back to what the router expects. Here is the example, I assume, that Elithar wanted to give.
func main() {
http.HandlerFunc(myDbHandler(Index, db))
}
type dbHandler func(w http.ResponseWriter, r *http.Request, db *sql.DB)
func myDbHandler(handler dbHandler, db *sql.DB) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
handler(w, r, db)
}
}
func Index(w http.ResponseWriter, r *http.Request, db *sql.DB) {
// handler code goes here
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论