【gin+gorm】向表中添加数据时报invalid memory address or nil pointer dereference
本帖最后由 thepoy 于 2020-7-19 10:07 编辑model
```go
type User struct {
gorm.Model
Username string `json:"username" form:"username" binding:"required" gorm:"type:varchar(20);not null;unique"`
Password string `json:"password" form:"password" binding:"required" gorm:"not null"`
Email string `json:"email" form:"email" binding:"required" gorm:"type:varchar(60);not null;unique"`
Phone string `json:"phone" form:"phone" binding:"required" gorm:"type:varchar(20);not null;unique"`
RegisterIP string `json:"register_ip" gorm:"type:varchar(15);not null"`
LastLoginTime *time.Time `json:"last_login_time"`
LastLoginIP string `json:"last_login_ip" gorm:"type:varchar(15)"`
Blogs []Blog
}
```
db
```go
var db *gorm.DB
func init() {
db, err := gorm.Open("mysql", "go:000aaa@tcp(127.0.0.1:3306)/blog")
if err != nil {
panic("Connecting database failed:" + err.Error())
}
db.DB().SetMaxOpenConns(100)
db.DB().SetMaxIdleConns(20)
db.AutoMigrate(&models.Blog{}, &models.User{}, &models.BlogType{})
db.Model(&models.Blog{}).AddUniqueIndex("title", "user_id", "blog_type_id")
}
func GetDB() *gorm.DB {
return db
}
```
handler
```go
func Regsiter(c *gin.Context) {
var form models.User
if err := c.ShouldBindWith(&form, binding.Form); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
db := utils.GetDB()
// 定义一个user实例
user := models.User{
Username: form.Username,
Password: form.Password,
Email: form.Email,
Phone: form.Phone,
RegisterIP: c.Request.RemoteAddr,
}
user.CreatedAt = time.Now()
fmt.Printf("%p", &user)
db.Create(&user) // 此行报错,但&user应该是能查到的有效指针才对,是user定义时出问题了吗?
c.JSON(http.StatusCreated, gin.H{
"msg": "register successful",
"username": form.Username,
})
}
```
运行后访问register,填好required的数据,报空指针或无效指针:
```shell
2020/07/18 22:08:12 2020/07/18 - 22:08:12 panic recovered:
POST /register HTTP/1.1
Host: localhost:8080
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 434
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryFnAqpmWULl4CibNl
Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop
Postman-Token: d06a2054-81f0-0c9c-7ba7-03ab09a993b2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: none
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36
runtime error: invalid memory address or nil pointer dereference
/usr/local/go/src/runtime/panic.go:212 (0x44aa19)
panicmem: panic(memoryError)
/usr/local/go/src/runtime/signal_unix.go:695 (0x44a868)
sigpanic: panicmem()
/home/thepoy/go/pkg/mod/github.com/jinzhu/gorm@v1.9.14/main.go:848 (0x57ccd6)
(*DB).clone: dialect: newDialect(s.dialect.GetName(), s.db),
/home/thepoy/go/pkg/mod/github.com/jinzhu/gorm@v1.9.14/main.go:204 (0x575d8e)
(*DB).NewScope: dbClone := s.clone()
/home/thepoy/go/pkg/mod/github.com/jinzhu/gorm@v1.9.14/main.go:482 (0x579ed2)
(*DB).Create: scope := s.NewScope(value)
/media/thepoy/软件/OneDrive - WULEL/code/go/src/go_blog_api/api/user.go:34 (0x9794c3)
Regsiter: db.Create(&user)
/home/thepoy/go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/context.go:161 (0x96449a)
(*Context).Next: c.handlers(c)
/home/thepoy/go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/recovery.go:83 (0x977b9f)
RecoveryWithWriter.func1: c.Next()
/home/thepoy/go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/context.go:161 (0x96449a)
(*Context).Next: c.handlers(c)
/home/thepoy/go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/logger.go:241 (0x976cd0)
LoggerWithConfig.func1: c.Next()
/home/thepoy/go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/context.go:161 (0x96449a)
(*Context).Next: c.handlers(c)
/home/thepoy/go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/gin.go:409 (0x96e275)
(*Engine).handleHTTPRequest: c.Next()
/home/thepoy/go/pkg/mod/github.com/gin-gonic/gin@v1.6.3/gin.go:367 (0x96d98c)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/go/src/net/http/server.go:2836 (0x78b082)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:1924 (0x7869eb)
(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_amd64.s:1373 (0x464270)
goexit: BYTE $0x90 // NOP
```
添加数据的代码,在单独测试时能够正常添加,放到gin里就报这个错。
请问是哪里的问题呢? 你的db实例有问题吧,db, err := gorm.Open("mysql", "go:000aaa@tcp(127.0.0.1:3306)/blog")这一行的 := 赋值的变量db是局部变量,不能赋值给上面的全局变量,用 = 号直接赋值试试
初始化数据库这块应该这样写,定一个全局可用的DB指针,初始化db之后赋值给这个全局可用的DB
var DB *gorm.DB
// Database 在中间件中初始化mysql链接
func Database() {
db, err := gorm.Open("mysql", "go:000aaa@tcp(127.0.0.1:3306)/blog")
if err != nil {
util.Log().Panic("连接数据库不成功", err)
}
if gin.Mode() == gin.ReleaseMode {
db.LogMode(false)
} else {
db.LogMode(true)
}
db.SingularTable(true)
//设置连接池
//空闲
db.DB().SetMaxIdleConns(50)
//打开
db.DB().SetMaxOpenConns(100)
//超时
db.DB().SetConnMaxLifetime(time.Second * 30)
DB = db
// 同步数据
migration()
}
使用的时候,使用这个全局可以用的DB就可以了,使用的示例如下:
funcShow(id string) {
var statistic model.AppManage
// 这个model.DB 就是初始化的那个全局变量DB
err := model.DB.Model(&statistic).
Select("project_id ,COUNT(*)").
Group("project_id").Where("created_at BETWEEN ? AND ?", server.StarTime, server.EndTime).
Scan(&results).Error
if err != nil {
return serializer.DBErr("", err)
}
}
lm93129 发表于 2020-7-19 01:45
初始化数据库这块应该这样写,定一个全局可用的DB指针,初始化db之后赋值给这个全局可用的DB
他写了一个专门获取db的方法,所以不是这个问题 我测试了下没啥问题啊
func GetDB() *gorm.DB {
db, err := gorm.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/blog")
if err != nil {
panic("Connecting database failed:" + err.Error())
}
db.DB().SetMaxOpenConns(100)
db.DB().SetMaxIdleConns(20)
db.AutoMigrate(&User{})
return db
}
type User struct {
gorm.Model
Username string `json:"username" form:"username" binding:"required" gorm:"type:varchar(20);not null;unique"`
Password string `json:"password" form:"password" binding:"required" gorm:"not null"`
Email string `json:"email" form:"email" binding:"required" gorm:"type:varchar(60);not null;unique"`
Phone string `json:"phone" form:"phone" binding:"required" gorm:"type:varchar(20);not null;unique"`
RegisterIP string `json:"register_ip" gorm:"type:varchar(15);not null"`
LastLoginTime *time.Time `json:"last_login_time"`
LastLoginIP string `json:"last_login_ip" gorm:"type:varchar(15)"`
}
func TestRegsiter(t *testing.T) {
app := gin.Default()
db := GetDB()
app.POST("/regsiter", func(c *gin.Context) {
var form User
if err := c.ShouldBindWith(&form, binding.Form); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
// 定义一个user实例
user := User{
Username: form.Username,
Password: form.Password,
Email: form.Email,
Phone: form.Phone,
RegisterIP: c.Request.RemoteAddr,
}
user.CreatedAt = time.Now()
fmt.Printf("%p", &user)
db.Create(&user) // 此行报错,但&user应该是能查到的有效指针才对,是user定义时出问题了吗?
c.JSON(http.StatusCreated, gin.H{
"msg": "register successful",
"username": form.Username,
})
})
_ = app.Run(":8888")
}
页:
[1]