为什么gorm db.First()会因“无效的内存地址或nil指针取消引用"而恐慌? [英] Why does gorm db.First() panic with "invalid memory address or nil pointer dereference"?

查看:1065
本文介绍了为什么gorm db.First()会因“无效的内存地址或nil指针取消引用"而恐慌?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不知道自己是否做过愚蠢的事情,或者是否发现gorm中的错误.虽然我很清楚无效的内存地址或nil指针取消引用"的含义,但是我完全不知道为什么它出现在这里.

I can't figure out if I've done something silly or if I've found a bug in gorm. While I'm very well aware of what "invalid memory address or nil pointer dereference" means, I am completely mystified as to why it appears here.

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

In short, I call db.First() and I receive a panic for no obvious reason.

我的代码的相关部分:

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()中打开,并存储为程序包变量.这似乎不太干净,但是似乎可以正常工作...

db is opened in main() in the package, and is stored as a package variable. This doesn't seem very clean, but it appears to work...

恐慌:

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"])

...where line 28 of my code is query := db.First(&m, vars["id"])

我查看了在gorm中注明的行First()功能,但这也不是很明显.

I reviewed the noted line in gorm and the First() function, but this also isn't terribly obvious.

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

为了弄清楚到底发生了什么,我对代码进行了以下更改:

In order to figure out what might be going on, I made the following changes to my code:

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

First attempt: Is it complaining about being passed a string? Let's give it an integer instead. After all, the example uses an integer.

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

再次在完全相同的地方用餐.

Panic again, at exactly the same place.

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

Second attempt: Did I create my variable m the wrong way? Maybe it really needs to be allocated with new first.

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

再次在完全相同的地方用餐.

Panic again, at exactly the same place.

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

Third attempt: I simply hardcoded the ID to be looked up, just in case gorilla/mux was misbehaving.

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

再次在完全相同的地方用餐.

Panic again, at exactly the same place.

最后,我用一个空的数据库表,一个填充的表请求一个存在的ID和一个填充的表请求一个不存在的ID进行了测试.在这三种情况下,我都感到同样的恐慌.

Finally, I tested with an empty database table, with a populated table requesting an ID that exists, and with a populated table requesting an ID that does not exist. In all three cases I receive the same panic.

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

The most interesting part of all is that apparently net/http is recovering the panic, and then my notFoundHandler() runs and I see its template output in the browser.

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

I am currently using the mattn/go-sqlite3 driver.

我的环境是Fedora RPM软件包中提供的带有cgo 1.4.2的Fedora 22 x86_64.

My environment is Fedora 22 x86_64 with cgo 1.4.2 as provided in Fedora RPM packages.

$ 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"

这是怎么回事?恐慌是从哪里来的?我该如何解决?

What's going on? Where is this panic coming from? How do I fix it?

推荐答案

您正在隐藏全局db变量:

var db = gorm.DB{} // garbage

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

Your initialisation in main() should be changed to:

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

否则,dbnil并导致恐慌.

这篇关于为什么gorm db.First()会因“无效的内存地址或nil指针取消引用"而恐慌?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆