一尘不染

使用Mux Router-如何将数据库传递给处理程序

go

目前,我尝试使用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",
            "GET",
            "/todos/{todoId}",
            controller.TodoShow,
        },  
        Route{
            "Create",
            "POST",
            "/todos",
            controller.TodoCreate,
        },  
    }

所以-如何将我的“ env”(或env.DB)传递给FuncHandlers?我尝试了很多东西,但没有一个起作用。


阅读 334

收藏
2020-07-02

共1个答案

一尘不染

您有三种选择:

  1. 将数据库连接池设置为全局,这样就不必传递它。sql.DB对于并发访问是安全的,这是最简单的方法。缺点是它使测试更加困难,并且混淆了池的“来源”-例如
        var db *sql.DB

    func main() {
        var err error
        db, err = sql.Open(...)
        // Now accessible globally, no need to pass it around
        // ...
     }
  1. 将您的处理程序包装在一个闭包中,以使内部处理程序可以访问它。您需要对此进行调整,以适应您的跨路线范围方法(这有点使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.
    }
  1. 创建一个接受处理程序的自定义处理程序类型-例如
        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, w http.ResponseWriter, r *http.Request) {
        res, err := env.DB.GetThings()
        // etc.
    }

请注意,(无耻的插件!)我已经详细介绍了最后一种方法,Alex
Edwards的博客文章也很出色,还介绍了在Go程序中访问数据库池的方法。

我能提供的唯一严格建议是,您应该避免在请求上下文中传递数据库池,这效率低下并且不是一种很好的做法(请求上下文是针对每个请求的临时对象)。

2020-07-02