You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 05:35:50