目前,我尝试在服务器上使用Go进行数据处理来创建一个小型Web项目.
我尝试将我的数据库连接传递给我的HandlerFunc(tions)但它没有按预期工作.我对golang很新,所以也许我不明白这个lang的一些基本原理.
我的主要功能如下:
func main() { db,err := config.NewDB("username:password@/databasename?charset=utf8&parseTime=True") if err != nil { log.Panic(err) } env := &config.Env{DB: db} router := NewRouter(env) log.Fatal(http.ListenAndServe(":8080",router)) }
我的路由器:
func NewRouter(env *config.Env) *mux.Router { router := mux.NewRouter().StrictSlash(true) for _,route := range routes { var handler http.Handler handler = route.HandlerFunc handler = Logger(handler,route.Name) router. Methods(route.Method). Path(route.Pattern). Name(route.Name). Handler(handler) } return router }
和我的路线:
type Route struct { Name string Method string Pattern string HandlerFunc http.HandlerFunc } type Routes []Route var routes = Routes{ Route{ "Index","GET","/",controller.Index,},Route{ "Show","/todos/{todoId}",controller.TodoShow,Route{ "Create","POST","/todos",controller.TodoCreate,}
那么 – 如何将我的“env”(或env.DB)传递给我的FuncHandlers?我尝试了很多东西,但没有一个能奏效.
解决方法
你有三个选择:
>使您的数据库连接池成为全局数据库,这样您就不必传递它. sql.DB对于并发访问是安全的,这是最简单的方法.缺点是它会使测试变得更加困难,并且模糊了池的来源 – 例如
var db *sql.DB func main() { var err error db,err = sql.Open(...) // Now accessible globally,no need to pass it around // ... }
>将处理程序包裹在一个闭包中,使内部处理程序可以访问它.你需要根据你的路线范围进行调整 – 这是一个有点迟钝的IMO,并且更难以看到存在哪些路线,但我离题了 – 例如:
func SomeHandler(db *sql.DB) http.HandlerFunc { fn := func(w http.ResponseWriter,r *http.Request) { res,err := db.GetThings() // etc. } return http.HandlerFunc(fn) } func main() { db,err := sql.Open(...) http.HandleFunc("/some-route",SomeHandler(db)) // etc. }
>创建一个接受处理程序的自定义处理程序类型 – 例如
type AppHandler struct { Handler func(env *config.Env,w http.ResponseWriter,r *http.Request) Env *config.Env // ServeHTTP allows your type to satisfy the http.Handler interface. func (ah *AppHandler) ServeHTTP(w http.ResponseWriter,r *http.Request) { ah.Handler(ah.Env,w,r) } func SomeHandler(env *config.Env,r *http.Request) { res,err := env.DB.GetThings() // etc. }
请注意(无耻的插件!)我已经written about the last approach in detail了,而且Alex Edwards在访问Go程序中的数据库池的方法上也有excellent blog post.
我可以给出的唯一严格的建议是,你应该回避在请求上下文中传递你的数据库池,这是低效的而不是良好的实践(请求上下文是针对临时的,每请求对象).