Service fails randomly: "runtime error: invalid memory address or nil pointer dereference"

Service fails randomly: "runtime error: invalid memory address or nil pointer dereference"

我正在 Restful API 服务器上工作,我不得不从 MongoDB 迁移到 MySQL。团队选择的 ORM 是 upper/db。我的问题是我的服务有时会失败,有时不会。

错误本身:runtime error: invalid memory address or nil pointer dereference

这是有时会给我错误的服务函数:

func (service *UserService) UpdateUser(req UpdateUserRequest) (response UpdateUserResponse, err error) {
    var user models.User
    defer service.db.Close()
    collection := service.db.Collection("users")

    result := collection.Find(req.ID)

    err = result.One(&user) // this is line 104
    if err != nil {
        return
    }

    count, err := result.Count()
    if err != nil {
        return
    }
    if count == 0 {
        err = errors.New("couldn't find user")
        return
    }

    if req.FirstName != "" && req.FirstName != user.FirstName {
        user.FirstName = req.FirstName
    }
    if req.LastName != "" && req.LastName != user.LastName {
        user.LastName = req.LastName
    }
    if req.UserType != "" && req.UserType != user.UserType {
        user.UserType = req.UserType
    }
    if req.Status != "" && req.Status != user.Status {
        user.Status = req.Status
    }

    user.UpdatedAt = time.Now()

    if err = result.Update(user); err != nil {
        return
    }

    user.Password = ""

    response.User = user
    return
}

我正在关注official documentation。奇怪的是第一次(服务器启动后)它成功更新了用户,下一次就没有了。

编辑:添加了错误转储:

runtime error: invalid memory address or nil pointer dereference
C:/Program Files/Go/src/runtime/panic.go:221 (0xfe993c)
        panicmem: panic(memoryError)
C:/Program Files/Go/src/runtime/signal_windows.go:254 (0xfe990c)
        sigpanic: panicmem()
C:/Program Files/Go/src/database/sql/sql.go:1260 (0x14452d3)
        (*DB).conn: db.mu.Lock()
C:/Program Files/Go/src/database/sql/sql.go:1695 (0x144831c)
        (*DB).query: dc, err := db.conn(ctx, strategy)
C:/Program Files/Go/src/database/sql/sql.go:1674 (0x144807e)
        (*DB).QueryContext: rows, err = db.query(ctx, query, args, cachedOrNewConn)
C:/Users/user/go/pkg/mod/github.com/upper/db/v4@v4.5.0/internal/sqladapter/compat/query_go18.go:39 (0x1486730)
        QueryContext: return p.QueryContext(ctx, query, args...)
C:/Users/user/go/pkg/mod/github.com/upper/db/v4@v4.5.0/internal/sqladapter/session.go:823 (0x14866eb)
        (*session).StatementQuery: rows, err = compat.QueryContext(sess.sqlDB, ctx, query, args)
C:/Users/user/go/pkg/mod/github.com/upper/db/v4@v4.5.0/internal/sqlbuilder/select.go:480 (0x147304f)
        (*selector).IteratorContext: rows, err := sess.StatementQuery(ctx, sq.statement(), sq.arguments()...)
C:/Users/user/go/pkg/mod/github.com/upper/db/v4@v4.5.0/internal/sqlbuilder/select.go:470 (0x1472d9a)
        (*selector).Iterator: return sel.IteratorContext(sel.SQL().sess.Context())
C:/Users/user/go/pkg/mod/github.com/upper/db/v4@v4.5.0/internal/sqlbuilder/paginate.go:176 (0x146d932)
        (*paginator).Iterator: return pq.sel.Iterator()
C:/Users/user/go/pkg/mod/github.com/upper/db/v4@v4.5.0/internal/sqladapter/result.go:243 (0x14809b5)
        (*Result).One: err = query.Iterator().One(dst)
C:/Users/user/go/src/github.com/myrepo/service/services/user_service.go:104 (0x15135be)
        (*UserService).UpdateUser: err = result.One(&user)
C:/Users/user/go/src/github.com/myrepo/service/handlers/users_handler.go:39 (0x1518e3c)
        handleUpdateUser.func1: user, err := service.UpdateUser(req)
C:/Users/user/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:168 (0x1515ff6)
        (*Context).Next: c.handlers[c.index](c)
C:/Users/user/go/pkg/mod/github.com/tpkeeper/gin-dump@v1.0.1/gindump.go:98 (0x15153b4)
        DumpWithOptions.func1: ctx.Next()
C:/Users/user/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:168 (0x14311a6)
        (*Context).Next: c.handlers[c.index](c)
C:/Users/user/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/logger.go:241 (0x1431189)
        LoggerWithConfig.func1: c.Next()
C:/Users/user/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:168 (0x1431f41)
        (*Context).Next: c.handlers[c.index](c)
C:/Users/user/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/recovery.go:99 (0x1431f2c)
        CustomRecoveryWithWriter.func1: c.Next()
C:/Users/user/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:168 (0x1430730)
        (*Context).Next: c.handlers[c.index](c)
C:/Users/user/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/gin.go:555 (0x1430398)
        (*Engine).handleHTTPRequest: c.Next()
C:/Users/user/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/gin.go:511 (0x142fed1)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
C:/Program Files/Go/src/net/http/server.go:2879 (0x120959a)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
C:/Program Files/Go/src/net/http/server.go:1930 (0x1204c47)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
C:/Program Files/Go/src/runtime/asm_amd64.s:1581 (0x1004640)
        goexit: BYTE    [=11=]x90   // NOP

编辑 2:添加了数据库连接

func Open(settings db.ConnectionURL) (db.Session, error) {
    db, err := mysql.Open(settings)
    if err != nil {
        return nil, err
    }

    if db.Ping() != nil {
        return nil, errors.New("error al conectar la base de datos")
    }

    return db, nil
}

我做错了什么?

函数 UpdateUser 在 return 上关闭了数据库。那是个大问题!对 UpdateUser 的后续调用出现恐慌,因为该函数在已关闭的数据库上调用方法。

删除这行代码以解决问题。

defer service.db.Close()