背景: 业务中需要以事务的方式同时更新多条记录,代码逻辑如下:

        tx := Db.Begin()

    rows, err := tx.Table(...).Where(...).Rows()
    if err != nil {
        tx.Rollback()
        return err
    }
    defer rows.Close()

    for rows.Next() {
        tmpTx := Db.Begin()
        a := StructA{}
        err = tmpTx.ScanRows(rows, &a)
        if err != nil {
            tmpTx.Rollback()
            tx.Rollback()
            return err
        }

        err = tmpTx.Table(...).Where(...).Update(...).Error
        if err != nil {
            tmpTx.Rollback()
            tx.Rollback()
            return err
        }

        tmpTx.Commit()
    }

    rows, err = tx.Table(...).Where().Rows()
    if err != nil {
        tx.Rollback()
        return err
    }
    defer rows.Close()

    for rows.Next() {
        tmpTx := Db.Begin()
        b := StructB{}
        err = tmpTx.ScanRows(rows, &b)
        if err != nil {
            tmpTx.Rollback()
            tx.Rollback()
            return err
        }

        err = tmpTx.Table(...).Where(...).Update(...).Error
        if err != nil {
            tmpTx.Rollback()
            tx.Rollback()
            return err
        }

        tmpTx.Commit()
    }

    rows, err = tx.Table(...).Where().Rows()
    if err != nil {
        tx.Rollback()
        return err
    }
    defer rows.Close()

    for rows.Next() {
        tmpTx := Db.Begin()
        c := StructC{}
        err = tmpTx.ScanRows(rows, &c)
        if err != nil {
            tmpTx.Rollback()
            tx.Rollback()
            return err
        }

        err = tmpTx.Table(...).Where(...).Update(...).Error
        if err != nil {
            tmpTx.Rollback()
            tx.Rollback()
            return err
        }

        tmpTx.Commit()
    }

    return tx.Commit().Error

现在发现更新过程中有时会报错 1040: Too many connections;但是需要更新的记录条数只有几条,所以我想问下 gorm 的 Rows 方法是会产生很多连接吗还是我使用的方法不对呢?目前数据库最大空闲连接数设置的是逻辑cpu数的2倍,最大连接数设置的是500,连接最大lifetime是2小时

Comment From: github-actions[bot]

The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ Search Before Asking

Comment From: ivila

@programmerX1123 不是rows的问题,我感觉是你的代码问题,你的代码产生了泄漏。。。 rows这个对象里面隐藏了一个mysql的连接,当你调用close后,这个连接会被关闭(或者是连接池没满的情况下返回给连接池) 但是注意看,你每次都“覆盖了”前面的rows变量。然后你代码里面一共生成了三次rows,但是close的只有一个。

所以我建议你调整一下逻辑: 1)添加MaxConnections限制最大连接数量(你是不是只设置了MaxIdle?) 2)修改一下rows变量的变量名,或者拆分到其它函数去。。。不要覆盖“未执行close方法的rows变量”,defer是要等到函数退出时才执行的,你这么写,只是把最后的那个rows close了三次而已。

Comment From: github-actions[bot]

The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ Search Before Asking