首页 文章

为什么gorm db.First()恐慌“无效的内存地址或无指针取消引用”?

提问于
浏览
6

我无法弄清楚我是否做过愚蠢的事情,或者我是否在gorm中发现了一个错误 . 虽然我非常清楚“无效的内存地址或无指针取消引用”是什么意思,但我对它出现在这里的原因完全不知所措 .

简而言之,我打电话给 db.First() ,我没有明显的理由感到恐慌 .

我的代码的相关部分:

package main

import (
    "fmt"
    "github.com/gorilla/mux"
    "github.com/jinzhu/gorm"
    "net/http"
    "os"
)

type message struct {
    gorm.Model
    Title string
    Body  string `sql:"size:0"` // blob
}

var db = gorm.DB{} // garbage

func messageHandler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    m := message{}
    query := db.First(&m, vars["id"])
    if query.Error != nil {
        if query.Error == gorm.RecordNotFound {
            notFoundHandler(w, r)
            return
        } else {
            fmt.Fprintf(os.Stderr, "database query failed: %v", query.Error)
            internalServerErrorHandler(w, r)
            return
        }
    }

    // actually do something useful
}

func main() {
    db, err := gorm.Open("sqlite3", "/tmp/gorm.db")
    // ...
}

db 在包中的 main() 中打开,并存储为包变量 . 这似乎不是很干净,但它似乎工作...

恐慌:

2015/07/16 20:56:12 http: panic serving [::1]:37326: runtime error: invalid memory address or nil pointer dereference
goroutine 26 [running]:
net/http.func·011()
        /usr/lib/golang/src/net/http/server.go:1130 +0xbb
github.com/jinzhu/gorm.(*DB).First(0xd28720, 0x79f220, 0xc2080b2600, 0xc2080ef220, 0x1, 0x1, 0xd)
        /home/error/go/src/github.com/jinzhu/gorm/main.go:200 +0x154
main.messageHandler(0x7f4f2e785bd8, 0xc208051c20, 0xc208035790)
        /home/error/go/src/myproject/messages.go:28 +0x2c1
net/http.HandlerFunc.ServeHTTP(0x9c3948, 0x7f4f2e785bd8, 0xc208051c20, 0xc208035790)
        /usr/lib/golang/src/net/http/server.go:1265 +0x41
github.com/gorilla/mux.(*Router).ServeHTTP(0xc2080d9630, 0x7f4f2e785bd8, 0xc208051c20, 0xc208035790)
        /home/error/go/src/github.com/gorilla/mux/mux.go:98 +0x297
net/http.serverHandler.ServeHTTP(0xc2080890e0, 0x7f4f2e785bd8, 0xc208051c20, 0xc208035790)
        /usr/lib/golang/src/net/http/server.go:1703 +0x19a
net/http.(*conn).serve(0xc208051b80)
        /usr/lib/golang/src/net/http/server.go:1204 +0xb57
created by net/http.(*Server).Serve
        /usr/lib/golang/src/net/http/server.go:1751 +0x35e

...我的代码的第28行是 query := db.First(&m, vars["id"])

我查看了the noted line in gormFirst() 函数,但这也不是很明显 .

return newScope.Set("gorm:order_by_primary_key", "ASC").
        inlineCondition(where...).callCallbacks(s.parent.callback.queries).db

为了弄清楚可能发生了什么,我对我的代码做了以下更改:

第一次尝试:是否抱怨传递一个字符串?让我们给它一个整数 . 毕竟,该示例使用整数 .

id, _ := strconv.Atoi(vars["id"])
    query := db.First(&m, id)

再次恐慌,在完全相同的地方 .

第二次尝试:我是否以错误的方式创建变量 m ?也许真的需要首先分配 new .

m := new(message)
    query := db.First(m, vars["id"])

再次恐慌,在完全相同的地方 .

第三次尝试:我只是硬编码要查找的ID,以防大猩猩/多路复用器行为不端 .

m := message{}
    query := db.First(&m, 3)

再次恐慌,在完全相同的地方 .

最后,我测试了一个空数据库表,其中一个填充表请求存在的ID,并且填充表请求一个不存在的ID . 在所有三种情况下,我都会收到同样的恐慌 .

最有趣的部分是显然net / http正在恢复恐慌,然后我的 notFoundHandler() 运行,我在浏览器中看到它的模板输出 .

我目前正在使用mattn/go-sqlite3驱动程序 .

我的环境是Fedora 22 x86_64,其中包含Fedora RPM软件包中提供的cgo 1.4.2 .

$ go version
go version go1.4.2 linux/amd64

$ go env
GOARCH="amd64"
GOBIN=""
GOCHAR="6"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/error/go"
GORACE=""
GOROOT="/usr/lib/golang"
GOTOOLDIR="/usr/lib/golang/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0"
CXX="g++"
CGO_ENABLED="1"

这是怎么回事?这种恐慌来自哪里?我如何解决它?

2 回答

  • 2

    你正在影响你的全局 db 变量:

    var db = gorm.DB{} // garbage
    

    您在 main() 中的初始化应更改为:

    var err error
    // Note the assignment and not initialise + assign operator
    db, err = gorm.Open("sqlite3", "/tmp/gorm.db")
    

    否则, dbnil 并导致恐慌 .

  • 13

    当变量为零时会发生这种情况 .

    query := db.First(&m, vars["id"])

    我怀疑db是零 . 我不知道你在哪里创造它 . 你需要做一些事情:

    db, err := gorm.Open("sqlite3", "/tmp/gorm.db")
    

    并导入“github.com/mattn/go-sqlite3”

    否则db将为零并且将发生恐慌 .

相关问题