panic: runtime error: invalid memory address or nil pointer dereference

来源:3-7 编码实战:从文件表中获取元数据

慕函数5852696

2020-03-31

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

goroutine 1 [running]:
database/sql.(*DB).SetMaxOpenConns(0x0, 0xa)
/usr/local/go/src/database/sql/sql.go:847 +0x26
github.com/xiaobaiadm/filestore-server/db/mysql.init.0()
/Users/baijunhua/newgo/src/github.com/xiaobaiadm/filestore-server/db/mysql/conn.go:14 +0x7a

附代码,14行报上面的错误,这块实在不知道那错了,遇到这种问题怎么排查呢,烦请老师给个思路。

func init() {
db,_ = sql.Open(“mysql”,“dog:1233456@localhost/fileserver”)
db.SetMaxOpenConns(10)
if err := db.Ping(); err != nil {
fmt.Println(“db connet,err:”,err)
os.Exit(1)
}
}
//返回数据库连接
func DbConn() *sql.DB {
return db
}

写回答

4回答

xiaomo

2020-04-02

可以看到sql.Open这个方法是有返回err信息的,源码:

func Open(driverName, dataSourceName string) (*DB, error) {
  driversMu.RLock()
  driveri, ok := drivers[driverName]
  driversMu.RUnlock()
  if !ok {
    return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
  }

  if driverCtx, ok := driveri.(driver.DriverContext); ok {
    connector, err := driverCtx.OpenConnector(dataSourceName)
    if err != nil {
      return nil, err
    }
    return OpenDB(connector), nil
  }

  return OpenDB(dsnConnector{dsn: dataSourceName, driver: driveri}), nil
}

里面返回来的error是由底层的sql driver来提供的,不同的driver可能会返回不同信息。 为了可以处理这种异常,我们这里的代码需要优化一下:

db, err := sql.Open("mysql", "test:test@tcp(127.0.0.1:3306)/fileserver?charset=utf8")
if err != nil {
  panic(err)  // 这里是否直接panic, 根据具体场景决定(也可以增加重试,或者只报warning后续再做处理)
}
db.SetMaxOpenConns(1000)
err := db.Ping()
if err != nil {
  fmt.Println("Failed to connect to mysql, err:" + err.Error())
  os.Exit(1)
}


0
0

xiaomo

2020-04-02

处理panic的一般做法是捕获异常,和其他语言的try-catch是类似的原理,比如:

func doSomething(index int) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("异常捕获:%s\n", r)
        }
    }()

    if index < 0 {
        panic("index必须大于0")
    }

    fmt.Println("方根运算:", math.Sqrt(float64(index)))
}

上述的init方法中,在创建Mysql连接时可以优化一下,加上类似逻辑.

0
0

慕函数5852696

提问者

2020-04-01

已经修复了 ,确实我之前某块地方写错了 ,今天早上尝试的时候好了,但是如果这块没有明显的错误,例如连接数据库出现账号密码错误等这样的明确的信息提示,直接来了一个panic ,出现这种情况我该怎么具体的排查呢,因为在这块开发中可能会遇到各种各样的panic ,有工具或者是什么可以排查代码么,让输出更明确一些,麻烦老师能给个思路,谢谢。
之前还遇到了 编译过程中的panic 

0
0

xiaomo

2020-04-01

同学你好,这个应该是与数据库建立连接没有成功。上面的14行的代码应该是这行?

db.SetMaxOpenConns(10)

这说明以下这行代码出了问题:

db,_ = sql.Open(“mysql”,“dog:1233456@localhost/fileserver”)

可以参考下git上的代码:https://git.imooc.com/coding-323/filestore-server/src/charter3/db/mysql/conn.go

var db *sql.DB

func init() {
	db, _ = sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/fileserver?charset=utf8")
	db.SetMaxOpenConns(1000)
	err := db.Ping()
	if err != nil {
		fmt.Println("Failed to connect to mysql, err:" + err.Error())
		os.Exit(1)
	}
}

把你的代码换成:

db,_ = sql.Open(“mysql”,“dog:1233456@tcp(127.0.0.1:3306)/fileserver?charset=utf8”)

这样试试看。还有就是检查用户名(dog)密码(1233456)是否正确?

0
0

Go实战仿百度云盘-实现企业级分布式云存储系统

紧随“云时代”技术潮流,分布式云存储系统,做第一代云程序员

1077 学习 · 494 问题

查看课程