Golang中如何在HTTP处理器中访问数据库连接?
解决Go中HTTP处理器无法访问数据库连接的问题
你遇到的是Go语言的作用域问题:db变量在main函数内声明,属于局部变量,getHandler函数不在它的作用域范围内,自然访问不到。下面给你两种常用的解决方式:
方法一:使用全局变量
把db变量声明在包级作用域(所有函数外部),这样整个包内的函数都能访问到。
示例代码:
package main import ( "database/sql" "fmt" "net/http" _ "github.com/lib/pq" // PostgreSQL驱动 ) // 包级声明db变量 var db *sql.DB func getHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "get req made") rows, err := db.Query("SELECT id, name, age FROM new_table LIMIT $1", 4) if err != nil { panic(err) } defer rows.Close() for rows.Next() { var id int var name string var age int err = rows.Scan(&id, &name, &age) if err != nil { panic(err) } fmt.Println(id, name, age) } err = rows.Err() if err != nil { panic(err) } } func main() { var err error // 初始化全局db变量 db, err = sql.Open("postgres", "your_connection_string") if err != nil { panic(err) } defer db.Close() // 注册处理器 http.HandleFunc("/get", getHandler) http.ListenAndServe(":8080", nil) }
这种方式简单直接,但要注意:全局变量在并发场景下要确保自身线程安全(PostgreSQL的sql.DB本身是并发安全的,所以这里没问题),但过多全局变量会增加代码耦合度,不利于维护。
方法二:通过闭包传递数据库连接(推荐)
利用闭包特性,在main函数中初始化db后,把它作为参数传入处理器的闭包中,避免使用全局变量,更符合Go的模块化设计。
示例代码:
package main import ( "database/sql" "fmt" "net/http" _ "github.com/lib/pq" ) // 定义一个接收db参数的函数,返回http.HandlerFunc func makeGetHandler(db *sql.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "get req made") rows, err := db.Query("SELECT id, name, age FROM new_table LIMIT $1", 4) if err != nil { panic(err) } defer rows.Close() for rows.Next() { var id int var name string var age int err = rows.Scan(&id, &name, &age) if err != nil { panic(err) } fmt.Println(id, name, age) } err = rows.Err() if err != nil { panic(err) } } } func main() { db, err := sql.Open("postgres", "your_connection_string") if err != nil { panic(err) } defer db.Close() // 传入db生成处理器 http.HandleFunc("/get", makeGetHandler(db)) http.ListenAndServe(":8080", nil) }
这种方式把数据库连接和处理器逻辑解耦,测试时还可以传入mock的db实例,更灵活。
额外说明
Node.js中你习惯的模块级变量访问,本质是因为Node的模块作用域是共享的,但Go的作用域规则更严格:只有在同一个作用域(或外层包级作用域)声明的变量才能被访问。上面两种方法都是围绕扩展db的作用域到处理器函数中展开的。
内容的提问来源于stack exchange,提问作者user19643485
相关产品推荐
相关产品推荐

