Go程序连接PostgreSQL后查询触发nil指针Panic问题
问题:Go连接PostgreSQL时的nil指针panic与303重定向问题
我用Go程序连接PostgreSQL数据库,调用GET方法访问/books/show端点时返回303重定向。程序启动显示“Database connection successful”,但查询数据库时触发runtime error: invalid memory address or nil pointer dereference panic。已确认用户凭据、权限及数据库格式均无问题,以下是相关信息,求解决方法:
curl请求输出
santosh@pkg*$:curl -i localhost:8080/books/show HTTP/1.1 303 See Other Content-Type: text/html; charset=utf-8 Location: /books Date: Sat, 19 Nov 2022 12:09:52 GMT Content-Length: 33 <a href="/books">See Other</a>.
程序运行报错
santosh@pkg*$:go run main.go Database connection successful. 2022/11/19 17:39:47 http: panic serving 127.0.0.1:44324: runtime error: invalid memory address or nil pointer dereference goroutine 35 [running]: net/http.(*conn).serve.func1() /usr/local/go/src/net/http/server.go:1850 +0xbf panic({0x6960e0, 0x8e5630}) /usr/local/go/src/runtime/panic.go:890 +0x262 database/sql.(*DB).conn(0x0, {0x7593d0, 0xc00011a000}, 0x1) /usr/local/go/src/database/sql/sql.go:1288 +0x53 database/sql.(*DB).query(0x6?, {0x7593d0, 0xc00011a000}, {0x6da967, 0x13}, {0x0, 0x0, 0x0}, 0x68?)
主程序代码
var db *sql.DB type Books struct { Isbn string Title string Author string Price float32 } func init() { var err error args := fmt.Sprintf("host=%s port=%d dbname=%s user='%s' password=%s sslmode=%s", "localhost", 5432, "bookstore", "santosh", "dts123", "disable") db, err := sql.Open("postgres", args) if err != nil { fmt.Printf("Creating Database %s", err) } if err = db.Ping(); err != nil { panic(err) } fmt.Println("Database connection succussful.") } func main() { http.HandleFunc("/", index) http.HandleFunc("/books", booksIndex) http.ListenAndServe(":8080", nil) } func index(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/books", http.StatusSeeOther) } func booksIndex(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { http.Error(w, http.StatusText(405), http.StatusMethodNotAllowed) return } rows, err := db.Query("SELECT * FROM books") if err != nil { http.Error(w, http.StatusText(500), 500) return } defer rows.Close() bks := make([]Books, 0) for rows.Next() { bk := Books{} err := rows.Scan(&bk.Isbn, &bk.Title, &bk.Author, &bk.Price) if err != nil { http.Error(w, http.StatusText(500), 500) return } bks = append(bks, bk) } if err = rows.Err(); err != nil { http.Error(w, http.StatusText(500), 500) return } }
问题分析与解决方法
1. nil指针panic问题
核心问题是init函数中的变量遮蔽:
db, err := sql.Open("postgres", args)
这里使用:=会创建一个局部变量db,而非给全局的var db *sql.DB赋值。全局db始终为nil,调用db.Query时触发panic。
修复步骤:
- 将
:=改为=,直接给全局变量赋值 - 完善错误处理,打开数据库失败时直接终止程序,避免后续无效执行
修改后的init函数:
func init() { var err error args := fmt.Sprintf("host=%s port=%d dbname=%s user='%s' password=%s sslmode=%s", "localhost", 5432, "bookstore", "santosh", "dts123", "disable") db, err = sql.Open("postgres", args) // 去掉:=,赋值给全局变量 if err != nil { panic(fmt.Sprintf("Failed to open database: %v", err)) // 直接panic终止 } if err = db.Ping(); err != nil { panic(err) } fmt.Println("Database connection successful.") }
2. /books/show的303重定向问题
当前代码仅注册了/和/books路由,未处理/books/show。Go默认ServeMux会将未匹配的请求转发到/,而/的handler会重定向到/books,因此返回303。
修复步骤:
将/books/show路由指向同一个查询逻辑handler:
func main() { http.HandleFunc("/", index) http.HandleFunc("/books", booksIndex) http.HandleFunc("/books/show", booksIndex) // 新增该路由 http.ListenAndServe(":8080", nil) }
内容的提问来源于stack exchange,提问作者santoshdts
相关产品推荐
相关产品推荐

