Go语言新手求助:如何解决invalid memory address or nil pointer dereference错误?
解决Go语言中的
invalid memory address or nil pointer dereference错误 嘿,作为Go新手遇到这个问题很正常,咱们一步步拆解并修复它~
问题根源分析
你的错误出在DbConn()函数里的两个关键问题:
- 变量赋值错误:你用了
db, err := sql.Open(...),这里的:=会在函数内部创建一个局部的db变量,完全覆盖了全局声明的var db *sql.DB。这就导致全局的db始终是nil,当AllPosts()调用db.Query()时,自然触发空指针引用错误。 - 过早关闭连接:你在
DbConn()里加了defer db.Close(),这会导致函数执行完毕后立刻关闭数据库连接——哪怕你的web服务还在运行,后续所有数据库操作都没有可用连接。
修复步骤及代码调整
1. 修正db.go中的数据库连接逻辑
修改全局变量赋值方式,移除过早的连接关闭,并添加连接有效性验证:
package models import ( "fmt" "database/sql" _ "github.com/go-sql-driver/mysql" "log" ) var db *sql.DB func DbConn() { var err error // 用=代替:=,给全局db变量赋值,而非创建局部变量 db, err = sql.Open("mysql", "root:@/posts") if err != nil { log.Fatal("初始化连接池失败:", err) } // 调用Ping()验证实际能连接到数据库(sql.Open只是初始化池,不立刻建立连接) if err = db.Ping(); err != nil { log.Fatal("无法连接到数据库:", err) } fmt.Println("数据库连接成功✅") } // 新增关闭连接的函数,用于程序退出时清理资源 func CloseDb() { if db != nil { if err := db.Close(); err != nil { log.Println("关闭数据库连接时出错:", err) } else { fmt.Println("数据库连接已关闭") } } }
2. 调整主程序syntax.go的资源管理
在主函数中确保数据库连接在整个服务生命周期内可用,并在程序退出时正确关闭:
package main import ( "blog/models" "fmt" "net/http" "os" "os/signal" "syscall" ) func main() { models.DbConn() // 使用defer确保程序正常退出时关闭连接 defer models.CloseDb() // 监听系统退出信号(比如Ctrl+C),保证异常退出时也能关闭连接 sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) go func() { <-sigChan fmt.Println("\n正在关闭服务...") models.CloseDb() os.Exit(0) }() http.HandleFunc("/books", postsIndex) fmt.Println("服务器启动在 http://localhost:3000") if err := http.ListenAndServe(":3000", nil); err != nil && err != http.ErrServerClosed { log.Fatal("服务器启动失败:", err) } } func postsIndex(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { http.Error(w, http.StatusText(405), 405) return } bks, err := models.AllPosts() if err != nil { http.Error(w, http.StatusText(500), 500) return } for _, bk := range bks { fmt.Fprintf(w, "%s, %s\n", bk.Title, bk.Description) } }
额外说明
- Go的
sql.DB是连接池,不是单个连接,不需要每次操作都打开关闭,保持全局的db变量复用即可。 sql.Open不会立刻建立数据库连接,必须调用Ping()才能确认连接是否有效,否则可能出现初始化成功但实际无法操作数据库的情况。
内容的提问来源于stack exchange,提问作者Ana be
相关产品推荐
相关产品推荐

