英文:
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) // 这是第 104 行
if err != nil {
return
}
count, err := result.Count()
if err != nil {
return
}
if count == 0 {
err = errors.New("找不到用户")
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
}
我正在遵循官方文档。奇怪的是第一次(服务器启动后)它成功更新用户,但下一次就不行了。
编辑:添加错误转储:
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 $0x90 // 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("连接数据库时出错")
}
return db, nil
}
我做错了什么?
英文:
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/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 $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?
答案1
得分: 4
函数UpdateUser
在返回时关闭了数据库。这是一个大问题!后续对UpdateUser
的调用会导致恐慌,因为函数在关闭的数据库上调用了方法。
删除这行代码以解决问题。
defer service.db.Close()
英文:
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()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论