Devil枫 2023-02-16 15:01 采纳率: 0%
浏览 31

gorm使用产生的数据库连接增加问题

使用gorm做服务端,遇到的问题。运行的一些api产生的数据库连接,一直不释放,导致服务运行久了,连接数一直增加,最后服务挂掉。
这个是初始化数据库连接

var SqlDB *sql.DB

func InitOracleDB() {
    databaseURL := fmt.Sprintf(`user="%s" password="%s" connectString="%s:%s/%s"`,
        global.AppConfig.Server.Oracle.Username,
        global.AppConfig.Server.Oracle.Password,
        global.AppConfig.Server.Oracle.Ip,
        global.AppConfig.Server.Oracle.Port,
        global.AppConfig.Server.Oracle.Service,
    )
    sqlDB, err := sql.Open("godror", databaseURL)
    if err != nil {
        log.Fatalln("数据库连接失败...,err:", err)
    }
    // SetMaxIdleConns 设置空闲连接池中连接的最大数量
    sqlDB.SetMaxIdleConns(10)
    // SetMaxOpenConns 设置打开数据库连接的最大数量。
    sqlDB.SetMaxOpenConns(30)
    // SetConnMaxLifetime 设置了连接可复用的最大时间。
    //sqlDB.SetConnMaxLifetime(time.Hour)
    SqlDB = sqlDB
    // 设置日志
    db, err := gorm.Open(oracle.New(oracle.Config{Conn: sqlDB}), &gorm.Config{
        Logger: gormLog(),
        NamingStrategy: schema.NamingStrategy{
            TablePrefix:   "",   // table name prefix, table for `User` would be `t_users`
            SingularTable: true, // use singular table name, table for `User` would be `user` with this option enabled
        },
    })
    if err != nil {
        log.Fatalln("数据库连接失败...,err:", err)
    }
    if global.AppConfig.Server.Mode == "release" {
        global.DB = db
    } else {
        global.DB = db.Debug()
    }
}

补充今天对api进行逐一分析:发现问题在于gorm中的会话模式,会产生新的数据库连接,创建一个Session后每次执行sql的时候都会导致tcp连接数量的增加,而且等待很久也不释放,问下大家有没有好的解决方法?

执行删除不增加:
    str := "delete from objs_attent where Id=123"
    err := global.DB.Exec(str).Error
执行查询不增加:
    str := `with a1 as (SELECT ObjId as id,ObjName as value from phar_define where  UseState > 0  ) select id as "id",value as "value",'phar' as "type" from a1 where  rownum<=10`
结构体直接查询不增加:
    var selectList []po.DicSignKind
    global.DB.Model(&po.DicSignKind{}).Find(&selectList)
执行关联,统计数量不增加:
    var totalCount int64
    sql2 := global.DB.
        Model(&po.PharDefine{}).
        Select("phar_define.ObjId,ObjCode,ObjName,dic_sign_kind.Name as Type,Sign,phar_define.RtuCode,phar_state.StateId as StateId,b.dept_name as OrganName,c.dept_name as ChannelName,phar_define.UseState,phar_define.Organ,Channel").
        Joins("left join phar_state on phar_state.ObjId=phar_define.ObjId").         // 连接航标状态获取终端号
        Joins("left join dic_sign_kind on phar_define.SignKind=dic_sign_kind.Code"). // 连接航标类型
        Joins("left join sys_dept b on phar_define.Organ=b.dept_id").
        Joins("left join sys_dept c on phar_define.Channel=c.dept_id")
    sql2.Count(&totalCount).
        Find(&result)
创建session并执行查询则会增加连接
     sql= global.DB.Table("phar_state").Where("RtuCode != 0")
     sql = sql.Session(&gorm.Session{PrepareStmt: true}) // 保存前面拼接的SQL条件
     err =sql.Where("RtuCode != 0").Find(&result).Error

比如如何锁定新的连接并删除该连接,我尝试用
kdb,err:=sql.Statement.DB.DB() 或者kdb,err :=global.DB.DB()
然后kdb.Close()
但是测试发现都是删除的初始数据库连接,而不是Session执行产生的新连接

  • 写回答

3条回答 默认 最新

  • Evaporator Core 2023-02-16 15:08
    关注

    根据你提供的代码,你的 SqlDB 是一个全局变量,可能在其他地方也被使用,而 global.DB 是一个 GORM 对象,也可能在其他地方被使用。如果在其他地方也使用了这些对象,那么这些对象的连接也会一直保持,导致连接数增加,最终导致服务挂掉。

    为了解决这个问题,你可以在使用完数据库连接之后,显式地关闭连接。例如,在使用 global.DB 之后,调用 global.DB.Close() 关闭连接。另外,你也可以尝试使用连接池,以便更好地管理数据库连接。对于 GORM,可以使用 DB.DB() 获取其底层的数据库连接对象,然后进行连接池配置,例如:

    db, err := gorm.Open(oracle.New(oracle.Config{Conn: sqlDB}), &gorm.Config{
        Logger: gormLog(),
        NamingStrategy: schema.NamingStrategy{
            TablePrefix:   "",   // table name prefix, table for `User` would be `t_users`
            SingularTable: true, // use singular table name, table for `User` would be `user` with this option enabled
        },
    })
    
    if err != nil {
        log.Fatalln("数据库连接失败...,err:", err)
    }
    
    sqlDB, err := db.DB()
    if err != nil {
        log.Fatalln("获取底层数据库连接失败...,err:", err)
    }
    
    sqlDB.SetMaxIdleConns(10)
    sqlDB.SetMaxOpenConns(30)
    

    这里通过 db.DB() 获取 GORM 的底层连接对象,然后进行连接池的配置。

    评论

报告相同问题?

问题事件

  • 修改了问题 2月17日
  • 创建了问题 2月16日

悬赏问题

  • ¥15 在hololens1上运行unity项目只有空窗口
  • ¥25 TABLEAU PREP无法打开
  • ¥15 关于#c语言#的问题:求完整代码条件好说
  • ¥15 (需要远程,AI不回)VB6二进制文件转换成功,但是C#转换总是失败
  • ¥15 关于#matlab#的问题:有没有什么其他办法能够保证不退出进程(相关搜索:matlab调用)
  • ¥15 依据报错在原代吗格式的基础上解决问题
  • ¥15 在虚拟机中安装flash code
  • ¥15 单片机stm32f10x编写光敏电阻调节3.3伏大功率灯亮度(光强越大灯越暗,白天正常光强灯不亮,使用ADC,PWM等模块)望各位找一下错误或者提供一个可实现功能的代码
  • ¥20 verilog状态机方法流水灯
  • ¥15 pandas代码实现不了意图