I am working on a Restful API server and I had to migrate from MongoDB to MySQL. The ORM the team picked up is upper/db. My issue is that my service fails some times, some times it doesn't.
The error itself: runtime error: invalid memory address or nil pointer dereference
This is the service function that gives me error some times:
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
}
I am following the official documentation. Something strange is the first time (after the server starts) it updates the user successfully, the next don't.
Edit: Error dump added:
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/[email protected]/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/[email protected]/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/[email protected]/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/[email protected]/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/[email protected]/internal/sqlbuilder/paginate.go:176 (0x146d932)
(*paginator).Iterator: return pq.sel.Iterator()
C:/Users/user/go/pkg/mod/github.com/upper/db/[email protected]/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/[email protected]/context.go:168 (0x1515ff6)
(*Context).Next: c.handlers[c.index](c)
C:/Users/user/go/pkg/mod/github.com/tpkeeper/[email protected]/gindump.go:98 (0x15153b4)
DumpWithOptions.func1: ctx.Next()
C:/Users/user/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:168 (0x14311a6)
(*Context).Next: c.handlers[c.index](c)
C:/Users/user/go/pkg/mod/github.com/gin-gonic/[email protected]/logger.go:241 (0x1431189)
LoggerWithConfig.func1: c.Next()
C:/Users/user/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:168 (0x1431f41)
(*Context).Next: c.handlers[c.index](c)
C:/Users/user/go/pkg/mod/github.com/gin-gonic/[email protected]/recovery.go:99 (0x1431f2c)
CustomRecoveryWithWriter.func1: c.Next()
C:/Users/user/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:168 (0x1430730)
(*Context).Next: c.handlers[c.index](c)
C:/Users/user/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:555 (0x1430398)
(*Engine).handleHTTPRequest: c.Next()
C:/Users/user/go/pkg/mod/github.com/gin-gonic/[email protected]/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 $0x90 // NOP
Edit 2: Added database connection
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
}
What am I doing wrong?
CodePudding user response:
The function UpdateUser
closes the database on return. That's big problem! The subsequent calls to UpdateUser
panic because the function calls methods on the closed database.
Delete this line of code to fix the issue.
defer service.db.Close()