栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

gorm踩坑 事务中Row/Rows未关闭导致panic

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

gorm踩坑 事务中Row/Rows未关闭导致panic

现象

web服务有个接口,service层开启事务,调用dao层两个接口。发现第二个dao层接口返回Error,在service层事务回滚时panic,该panic无法被recover。

代码详情

事务中有两条sql,第一条调用Rows查询,第二条普通查询,代码如下:

func TestGorm(db *gorm.DB) ([]*User, error) {
    tx := db.Begin()
    //第1条SQL
    rows, err := tx.Table("user").Select("max(age) as max_age").Rows()
    if err != nil {
        tx.Rollback()
        return nil, err
    }
    var maxAge int8
    if rows.Next() {
        err = rows.Scan(&maxAge)
        if err != nil {
            tx.Rollback()
            return nil, err
        }
    }
    //TAG rows没有close
    var users []*User
    //第2条SQL
    tx = tx.Table("user").Where("age = ?", maxAge).Find(&users)
    if tx.Error != nil {
        //此处回滚
        tx.Rollback()
        return nil, tx.Error
    }
    db.Commit()
    return users, nil
}
日志

1. 第二条SQL执行失败,tx.Error为driver: bad connection,并打印如下日志

[mysql] 2021/12/30 13:59:22 packets.go:445: busy buffer

2.  执行tx.Rollback()时panic,日志如下:

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

goroutine 100 [running]:
code.byted.org/gopkg/mysql-driver.sqlAfter(0xc0004ea340, 0x0, 0x0)
    /Users/bytedance/go/pkg/mod/code.byted.org/gopkg/mysql-driver@v1.2.1/middleware.go:66 +0x3f
code.byted.org/gopkg/mysql-driver.(*mysqlStmt).query.func1.1()
    /Users/bytedance/go/pkg/mod/code.byted.org/gopkg/mysql-driver@v1.2.1/statement.go:130 +0x3b
code.byted.org/gopkg/mysql-driver.(*mysqlStmt).QueryContext.func1()
    /Users/bytedance/go/pkg/mod/code.byted.org/gopkg/mysql-driver@v1.2.1/connection_go18.go:152 +0x4b
code.byted.org/gopkg/mysql-driver.(*mysqlRows).Close(0xc0004f2780, 0x0, 0x0)
    /Users/bytedance/go/pkg/mod/code.byted.org/gopkg/mysql-driver@v1.2.1/rows.go:70 +0x134
database/sql.(*Rows).close.func1()
    /usr/local/go/src/database/sql/sql.go:3178 +0x3c
database/sql.withLock(0x19912c0, 0xc0001c6000, 0xc000502700)
    /usr/local/go/src/database/sql/sql.go:3294 +0x69
database/sql.(*Rows).close(0xc000167300, 0x0, 0x0, 0x0, 0x0)
    /usr/local/go/src/database/sql/sql.go:3177 +0x114
database/sql.(*Rows).awaitDone(0xc000167300, 0x19994a8, 0xc0004e8700, 0x19994a8, 0xc000334040)
    /usr/local/go/src/database/sql/sql.go:2831 +0xd4
created by database/sql.(*Rows).initContextClose
    /usr/local/go/src/database/sql/sql.go:2815 +0xc9

原因

rows会维护这个数据库连接,当 tx 想再次调用当前连接进行数据库操作的时候,因为连接还没有断开,没有调用 rows.Close(),tx 无法再从连接池里获取当前连接。参考:Golang 报错 | 操作mysql提示busy buffer_MyBlog-CSDN博客

解决方法

在“//TAG rows没有close”行增加“rows.Close()”

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/990657.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号