Golang中如何在多个HTTP处理器之间共享数据库连接

Golang中如何在多个HTTP处理器之间共享数据库连接 大家好,

我对 Golang 还比较陌生,正在构建一个使用 MySQL 数据库存储数据的小型网站。

在所有处理程序之间共享数据库连接(MySQL)并正确关闭它的最佳方法是什么?

我希望避免在每个处理程序中都打开连接。

谢谢

3 回复

感谢您的建议,我的做法略有不同。我将数据库连接封装在一个结构体中,如下所示:

type Store struct {
    connection *sql.DB
}

并在我的服务器结构体(放置HTTP处理程序的地方)中使用它:

type Server struct {
    tlp   *template.Template
    store *database.Store
}

更多关于Golang中如何在多个HTTP处理器之间共享数据库连接的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


func withDBContext(fn func(db *sql.DB)) error {
        conn := GetDB()
        // 这里不要调用 defer conn.Close(),fn 可以并发执行
        return fn(conn)
    }

然后你可以像下面这样使用上述函数:

func foo() {
    withDBContext(func(db *sql.DB) error {
        defer db.Close() // 如果每次都必须关闭数据库,否则你不需要在这里关闭 db,这是一个连接池,它会为你处理连接
        // 用你的代码执行一些操作
    })
}

我就是这样做的。

在Go中,在多个HTTP处理器之间共享数据库连接的最佳方法是使用全局变量或依赖注入模式。以下是一个使用全局变量的示例:

package main

import (
    "database/sql"
    "log"
    "net/http"
    
    _ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

func init() {
    var err error
    db, err = sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
    if err != nil {
        log.Fatal(err)
    }
    
    // 测试连接
    err = db.Ping()
    if err != nil {
        log.Fatal(err)
    }
}

func main() {
    defer db.Close()
    
    http.HandleFunc("/users", usersHandler)
    http.HandleFunc("/products", productsHandler)
    
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func usersHandler(w http.ResponseWriter, r *http.Request) {
    // 使用全局db变量执行查询
    rows, err := db.Query("SELECT id, name FROM users")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    defer rows.Close()
    
    // 处理结果
    // ...
}

func productsHandler(w http.ResponseWriter, r *http.Request) {
    // 同样使用全局db变量
    rows, err := db.Query("SELECT id, name, price FROM products")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    defer rows.Close()
    
    // 处理结果
    // ...
}

或者使用依赖注入的方式:

package main

import (
    "database/sql"
    "log"
    "net/http"
    
    _ "github.com/go-sql-driver/mysql"
)

type App struct {
    DB *sql.DB
}

func NewApp() *App {
    db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
    if err != nil {
        log.Fatal(err)
    }
    
    err = db.Ping()
    if err != nil {
        log.Fatal(err)
    }
    
    return &App{DB: db}
}

func (app *App) usersHandler(w http.ResponseWriter, r *http.Request) {
    rows, err := app.DB.Query("SELECT id, name FROM users")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    defer rows.Close()
    
    // 处理结果
    // ...
}

func (app *App) productsHandler(w http.ResponseWriter, r *http.Request) {
    rows, err := app.DB.Query("SELECT id, name, price FROM products")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    defer rows.Close()
    
    // 处理结果
    // ...
}

func main() {
    app := NewApp()
    defer app.DB.Close()
    
    http.HandleFunc("/users", app.usersHandler)
    http.HandleFunc("/products", app.productsHandler)
    
    log.Fatal(http.ListenAndServe(":8080", nil))
}

这两种方法都能确保数据库连接在程序启动时只创建一次,在所有处理器之间共享,并在程序结束时正确关闭。依赖注入的方式在大型项目中更具可测试性和可维护性。

回到顶部