AutoMigrate() 报错 Panic Error: Memory Address or Nil Pointer Dereference

1. 运行环境

Windows 11, WSL2

No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.4 LTS
Release:        20.04
Codename:       focal

2. 问题描述?

我再通过运行Go的时候获取了一下的报错,panic: runtime error: invalid memory address or nil pointer dereference
我觉得这是因为&user.User{}所导致的,

  • 尝试在在SO寻找类似的报错,结果而言并不是shadowing的问题
  • 尝试了把struct在当地文件运行,也有类似的错误
  • 检查了前几集课程的代码,复制后粘贴,以排除是人疏忽

按照教学,此行database.DB.AutoMigrate(&user.User{})应该是需要放在最后一行的

func SetupDB() {

    ...

    database.Connect(dbConfig, logger.Default.LogMode(logger.Info))
    database.SQLDB.SetMaxOpenConns(config.GetInt("database.mysql.max_open_connections"))
    database.SQLDB.SetMaxIdleConns(config.GetInt("database.mysql.max_idle_connections"))
    database.SQLDB.SetConnMaxLifetime(time.Duration(config.GetInt("database.mysql.max_life_seconds")) * time.Second)

    database.DB.AutoMigrate(&user.User{})
}

3. 您期望得到的结果?

我期望的结果是能顺利migrate user table到MySQL的数据库中

4. 您实际得到的结果?

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x7fb2b8]

goroutine 1 [running]:
...
subscription-manager/bootstrap.SetupDB()
        /root/workspace/go/src/github.com/weehong/subscription-manager/bootstrap/database.go:39 +0x44a
main.main()
        /root/workspace/go/src/github.com/weehong/subscription-manager/main.go:24 +0xf4
WeeHong
WeeHong
最佳答案

經過不斷的嘗試,我終於找到問題的所在了
原因是因為我在database用了錯誤的syntax

func Connect(dbConfig gorm.Dialector, _logger gormlogger.Interface) {
    var err error

    // 錯誤 
    // DB, err := gorm.Open
    DB, err = gorm.Open(dbConfig, &gorm.Config{
        Logger: _logger,
    })

    if err != nil {
        fmt.Println(err.Error())
    }

    SQLDB, err = DB.DB()
    if err != nil {
        fmt.Println(err.Error())
    }
}

學到新的東西了 :relaxed:

原來用var DB *gorm.DB之後,還能用:=來取代原來的數據
而我的問題就是在這裡,這麼做的話,我的DB就會重新初始化,而var DB還是null的。
stackoverflow.com/a/42780598/46523...

這就會讓DB變成shadowing了,從而導致nil pointer的問題報錯

2年前 评论
讨论数量: 9
WeeHong

經過不斷的嘗試,我終於找到問題的所在了
原因是因為我在database用了錯誤的syntax

func Connect(dbConfig gorm.Dialector, _logger gormlogger.Interface) {
    var err error

    // 錯誤 
    // DB, err := gorm.Open
    DB, err = gorm.Open(dbConfig, &gorm.Config{
        Logger: _logger,
    })

    if err != nil {
        fmt.Println(err.Error())
    }

    SQLDB, err = DB.DB()
    if err != nil {
        fmt.Println(err.Error())
    }
}

學到新的東西了 :relaxed:

原來用var DB *gorm.DB之後,還能用:=來取代原來的數據
而我的問題就是在這裡,這麼做的話,我的DB就會重新初始化,而var DB還是null的。
stackoverflow.com/a/42780598/46523...

這就會讓DB變成shadowing了,從而導致nil pointer的問題報錯

2年前 评论

你把 bootstrap 目录中的 database.go 完整代码贴出来;这错误大概是 main.go 或者 database.go 中你重新声明了一个局部的变量,而没用方法修改过的全局变量。

2年前 评论
WeeHong

这是我database.go的代码

我也是复制粘贴过了

package bootstrap

import (
    "errors"
    "fmt"
    "os/user"
    "subscription-manager/pkg/config"
    "subscription-manager/pkg/database"
    "time"

    "gorm.io/driver/mysql"
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
    "gorm.io/gorm/logger"
)

// SetupDB 初始化数据库和 ORM
func SetupDB() {

    var dbConfig gorm.Dialector
    switch config.Get("database.connection") {
    case "mysql":
        // 构建 DSN 信息
        dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=%v&parseTime=True&multiStatements=true&loc=Local",
            config.Get("database.mysql.username"),
            config.Get("database.mysql.password"),
            config.Get("database.mysql.host"),
            config.Get("database.mysql.port"),
            config.Get("database.mysql.database"),
            config.Get("database.mysql.charset"),
        )
        dbConfig = mysql.New(mysql.Config{
            DSN: dsn,
        })
    case "sqlite":
        // 初始化 sqlite
        database := config.Get("database.sqlite.database")
        dbConfig = sqlite.Open(database)
    default:
        panic(errors.New("database connection not supported"))
    }

    // 连接数据库,并设置 GORM 的日志模式
    database.Connect(dbConfig, logger.Default.LogMode(logger.Info))

    // 设置最大连接数
    database.SQLDB.SetMaxOpenConns(config.GetInt("database.mysql.max_open_connections"))
    // 设置最大空闲连接数
    database.SQLDB.SetMaxIdleConns(config.GetInt("database.mysql.max_idle_connections"))
    // 设置每个链接的过期时间
    database.SQLDB.SetConnMaxLifetime(time.Duration(config.GetInt("database.mysql.max_life_seconds")) * time.Second)

    database.DB.AutoMigrate(&user.User{})
}
2年前 评论

file

标注的那行代码替换成"subscription-manager/app/models/user" 试一试。

2年前 评论
WeeHong

不好意思,之前从"subscription-manager/app/models/user"改回去os/user的时候忘记该回去了

其实这两个我都试过了,还是获得了一样的错误提报 会不会是因为Gorm升级了,从而导致AutoMigrate的使用方法不一样了?

2年前 评论
WeeHong

經過不斷的嘗試,我終於找到問題的所在了
原因是因為我在database用了錯誤的syntax

func Connect(dbConfig gorm.Dialector, _logger gormlogger.Interface) {
    var err error

    // 錯誤 
    // DB, err := gorm.Open
    DB, err = gorm.Open(dbConfig, &gorm.Config{
        Logger: _logger,
    })

    if err != nil {
        fmt.Println(err.Error())
    }

    SQLDB, err = DB.DB()
    if err != nil {
        fmt.Println(err.Error())
    }
}

學到新的東西了 :relaxed:

原來用var DB *gorm.DB之後,還能用:=來取代原來的數據
而我的問題就是在這裡,這麼做的話,我的DB就會重新初始化,而var DB還是null的。
stackoverflow.com/a/42780598/46523...

這就會讓DB變成shadowing了,從而導致nil pointer的問題報錯

2年前 评论

我也碰到过类似的报错,恶补了指针知识

2年前 评论

我也遇到了,找了好久,发现是初始化数据库那里放错位置了 :sweat_smile:

1年前 评论

账号密码错误也有可能报这个错误 :joy:

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!