Golang中解决无效内存地址或空指针解引用问题

Golang中解决无效内存地址或空指针解引用问题 我可以在不使用rest api的情况下连接并获取数据库数据。但是当涉及到rest时,我遇到了:

2019/03/02 15:25:29 http: panic serving 127.0.0.1:49348: runtime error: invalid memory address or nil pointer dereference goroutine 4 [running]: net/http.(*conn).serve.func1(0xc000284000) C:/Go/src/net/http/server.go:1746 +0xd7 panic(0x6c5180, 0x947770) C:/Go/src/runtime/panic.go:513 +0x1c7 database/sql.(*DB).conn(0x0, 0x76f940, 0xc00004a080, 0xc0001b7001, 0x2, 0x30000, 0x2) C:/Go/src/database/sql/sql.go:1081 +0x41 database/sql.(*DB).query(0x0, 0x76f940, 0xc00004a080, 0x721823, 0x13, 0x0, 0x0, 0x0, 0x6ef801, 0x20, …) C:/Go/src/database/sql/sql.go:1514 +0x6d database/sql.(*DB).QueryContext(0x0, 0x76f940, 0xc00004a080, 0x721823, 0x13, 0x0, 0x0, 0x0, 0x6addc0, 0x1, …) C:/Go/src/database/sql/sql.go:1496 +0xda database/sql.(*DB).Query(0x0, 0x721823, 0x13, 0x0, 0x0, 0x0, 0x40c17f, 0x80, 0x703660) C:/Go/src/database/sql/sql.go:1510 +0x89 main.getBooks(0x76f780, 0xc0002a8000, 0xc000294200) C:/Users/User/go/src/books-list - 1/main.go:100 +0xb6 net/http.HandlerFunc.ServeHTTP(0x734af8, 0x76f780, 0xc0002a8000, 0xc000294200) C:/Go/src/net/http/server.go:1964 +0x4b github.com/gorilla/mux.(*Router).ServeHTTP(0xc000204300, 0x76f780, 0xc0002a8000, 0xc000294000) c:/users/user/go/src/github.com/gorilla/mux/mux.go:212 +0xd7 net/http.serverHandler.ServeHTTP(0xc00004f040, 0x76f780, 0xc0002a8000, 0xc000294000) C:/Go/src/net/http/server.go:2741 +0xb2 net/http.(*conn).serve(0xc000284000, 0x76f900, 0xc00028a040) C:/Go/src/net/http/server.go:1847 +0x64d created by net/http.(*Server).Serve C:/Go/src/net/http/server.go:2851 +0x2fc

在rest方法中,我做的操作与没有使用rest时完全相同(用于测试)。

上述错误中最有趣的部分是,为什么程序在服务127.0.0.1:49348,而我的代码中使用的是http.ListenAndServe("localhost:8000", router)

当我停止程序并重新启动时,我得到了类似的结果,地址变成了127.0.0.1:49372。我认为每次端口都会不同。实际上,每次我请求rest api时,错误中的端口都是不同的。

看起来错误发生在rest方法的以下行:

rows, err := db.Query(“select * from books”)

因为下一行是

fmt.Println(“attention”)

而我没有在控制台看到输出。


更多关于Golang中解决无效内存地址或空指针解引用问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

实际上,问题的原因是数据库对象为nil。我不会说堆栈跟踪对此描述得特别清晰…

更多关于Golang中解决无效内存地址或空指针解引用问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


通常当我在数据库查询中遇到这个错误时,是因为书籍表不存在或与数据库本身相关的问题。我建议进入数据库管理系统检查正确的数据库中是否包含书籍表。

否则,我建议提供有关该 REST API 中处理函数的更多信息。

你指的是你的 REST API 中的读取函数吗?

这个错误是由于在REST处理程序中使用了未初始化的数据库连接对象(db变量为nil)导致的。从堆栈跟踪可以看到,在main.getBooks函数中调用db.Query()时,dbnil

以下是解决方案和示例代码:

package main

import (
    "database/sql"
    "fmt"
    "log"
    "net/http"

    _ "github.com/lib/pq" // 根据你的数据库类型导入相应的驱动
    "github.com/gorilla/mux"
)

var db *sql.DB

func initDB() {
    var err error
    // 替换为你的数据库连接字符串
    connStr := "user=youruser dbname=yourdb password=yourpass host=localhost sslmode=disable"
    db, err = sql.Open("postgres", connStr)
    if err != nil {
        log.Fatal(err)
    }

    err = db.Ping()
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Println("数据库连接成功")
}

func getBooks(w http.ResponseWriter, r *http.Request) {
    // 检查db是否为nil
    if db == nil {
        http.Error(w, "数据库连接未初始化", http.StatusInternalServerError)
        return
    }

    rows, err := db.Query("SELECT * FROM books")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    defer rows.Close()

    fmt.Println("attention") // 现在这行会执行

    var books []Book
    for rows.Next() {
        var book Book
        err := rows.Scan(&book.ID, &book.Title, &book.Author)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        books = append(books, book)
    }

    // 返回JSON响应
    w.Header().Set("Content-Type", "application/json")
    // 这里添加JSON编码逻辑
}

type Book struct {
    ID     int    `json:"id"`
    Title  string `json:"title"`
    Author string `json:"author"`
}

func main() {
    // 初始化数据库连接
    initDB()
    defer db.Close()

    router := mux.NewRouter()
    router.HandleFunc("/books", getBooks).Methods("GET")

    fmt.Println("服务器启动在 localhost:8000")
    log.Fatal(http.ListenAndServe("localhost:8000", router))
}

关于端口号的问题:错误中显示的端口(如127.0.0.1:49348)是客户端连接的端口,这是由操作系统动态分配的。你的服务器确实运行在localhost:8000,但客户端会使用随机的高端口号连接到你的服务器。

关键修改点:

  1. 确保在调用任何数据库操作前初始化db变量
  2. 在数据库操作前添加nil检查
  3. 使用initDB()函数正确建立数据库连接
  4. 在主函数中调用initDB()并添加defer db.Close()

如果你已经有一个数据库初始化函数,确保它在REST处理程序被调用之前执行。

回到顶部