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

Go语言新手求助:如何解决invalid memory address or nil pointer dereference错误?

解决Go语言中的invalid memory address or nil pointer dereference错误

嘿,作为Go新手遇到这个问题很正常,咱们一步步拆解并修复它~

问题根源分析

你的错误出在DbConn()函数里的两个关键问题:

  1. 变量赋值错误:你用了db, err := sql.Open(...),这里的:=会在函数内部创建一个局部的db变量,完全覆盖了全局声明的var db *sql.DB。这就导致全局的db始终是nil,当AllPosts()调用db.Query()时,自然触发空指针引用错误。
  2. 过早关闭连接:你在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:09:03