golang 原生database\sql 的重连机制实现

 更新时间:2026年02月12日 11:38:34   作者:落舞者  
本文主要介绍了golang 原生database\sql 的重连机制实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1. 连接池的自动管理

Go 的 database/sql确实有部分自动重连能力,但有限制:

✅ 支持的情况

  1. 连接失效自动重试

    • 如果驱动返回 ErrBadConndatabase/sql 会自动重试操作
    • 连接池会自动检测并移除失效的连接
    • 下次使用时,会从连接池获取新连接(如果连接池中有可用连接)
  2. 连接池自动补充

    • 当连接池中的连接失效时,会在需要时自动创建新连接
    • 只要 sql.DB 对象没有被关闭,连接池会持续工作

❌ 不支持的情况

  1. 整个连接池被关闭

    • 如果调用了 db.Close(),整个连接池被关闭
    • 不会自动重新打开,需要重新创建 sql.DB 对象
  2. 长时间停机后的恢复

    • 如果 MySQL 停机时间很长,连接池中的所有连接都可能失效
    • 虽然连接池会尝试创建新连接,但没有主动的健康检查
    • 只有在实际使用时才会发现连接失效并重试

2. 实际场景分析

场景1: MySQL 短暂停机(几秒到几分钟)

// 程序已连接
db, _ := sql.Open("mysql", "dsn...")

// MySQL 停机
// ... MySQL 重启 ...

// 下次使用时
rows, err := db.Query("SELECT * FROM users")
// ✅ 可能成功:如果连接池中有可用连接,会自动重试
// ⚠️ 可能失败:如果所有连接都失效,需要等待重试或手动处理

行为

  • database/sql 会检测到连接失效(返回 ErrBadConn
  • 自动重试操作,尝试从连接池获取新连接
  • 如果连接池中有可用连接,会成功
  • 如果所有连接都失效,会创建新连接

场景2: MySQL 长时间停机(几分钟到几小时)

// 程序已连接
db, _ := sql.Open("mysql", "dsn...")

// MySQL 长时间停机
// ... 所有连接都失效 ...

// MySQL 重启后
rows, err := db.Query("SELECT * FROM users")
// ⚠️ 第一次调用可能失败,需要重试
// ✅ 后续调用会成功(连接池已恢复)

行为

  • 连接池中的所有连接都已失效
  • 第一次调用时,会尝试使用失效的连接,失败
  • database/sql 检测到 ErrBadConn,自动重试
  • 重试时会创建新连接,成功

场景3: 调用 db.Close() 后

// 程序已连接
db, _ := sql.Open("mysql", "dsn...")

// 关闭连接池
db.Close()

// 尝试使用
rows, err := db.Query("SELECT * FROM users")
// ❌ 失败:sql: database is closed
// ❌ 不会自动重连,需要重新创建 sql.DB 对象

行为

  • sql.DB 对象被标记为已关闭
  • 所有操作都会返回 sql: database is closed 错误
  • 不会自动重新打开

实际使用建议

1. 对于 MySQL 短暂停机

原生机制通常足够

db, _ := sql.Open("mysql", "dsn...")
// 不需要特殊处理,database/sql 会自动处理连接失效

2. 对于 MySQL 长时间停机

建议添加重试逻辑

db, _ := sql.Open("mysql", "dsn...")

// 添加重试逻辑
var rows *sql.Rows
var err error
for i := 0; i < 3; i++ {
    rows, err = db.Query("SELECT * FROM users")
    if err == nil {
        break
    }
    time.Sleep(time.Second)
}

3. 对于需要 Close() 的场景

原生机制不支持

db.Close()
// ❌ 无法恢复,需要重新创建

总结

database/sql 原生机制

  • ✅ 处理连接失效和自动重试
  • ✅ 连接池自动管理
  • ❌ 不支持 Close() 后恢复
  • ❌ 没有主动健康检查

到此这篇关于golang 原生database\sql 的重连机制实现的文章就介绍到这了,更多相关golang 重连机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一文带你深入了解Golang中的参数传递机制

    一文带你深入了解Golang中的参数传递机制

    值传递和引用传递是编程语言中两种主要的参数传递方式,决定了函数调用过程中实参如何影响形参以及函数内部对形参的修改是否会影响到原始实参,下面就跟随小编一起深入了解下golang中参数传递机制吧
    2024-01-01
  • Go语言如何通过通信共享内存

    Go语言如何通过通信共享内存

    这篇文章主要为大家介绍了Go语言如何通过通信共享内存实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • Golang交叉编译之跨平台编译使用详解

    Golang交叉编译之跨平台编译使用详解

    这篇文章主要为大家介绍了Golang交叉编译之跨平台编译使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • go语言之go(goroutine)控制异步详解

    go语言之go(goroutine)控制异步详解

    Go语言通过goroutine实现并发,允许异步执行函数,但单独使用会引发顺序问题,需结合WaitGroup确保主线程等待所有并发任务完成后再输出结果,从而正确同步执行流程
    2025-07-07
  • go语言中slice,map,channl底层原理

    go语言中slice,map,channl底层原理

    这篇文章主要介绍了go语言中slice,map,channl底层原理,slice,map,channl是我们Go语言中最最常用的几个数据结构,对于其更多相关内容需要的小伙伴可以参考下面文章详细内容
    2022-06-06
  • Golang Defer基础操作详解

    Golang Defer基础操作详解

    在golang当中,defer代码块会在函数调用链表中增加一个函数调用。这个函数调用不是普通的函数调用,而是会在函数正常返回,也就是return之后添加一个函数调用。因此,defer通常用来释放函数内部变量
    2022-10-10
  • Go语言学习之接口类型(interface)详解

    Go语言学习之接口类型(interface)详解

    接口是用来定义行为的类型,定义的行为不由接口直接实现,而由通过方法由定义的类型实现,本文就来和大家详细讲讲Go语言中接口的使用吧
    2023-03-03
  • golang中常见的logrus日志库

    golang中常见的logrus日志库

    这篇文章主要介绍了golang中常见的logrus日志库的相关资料,需要的朋友可以参考下
    2023-05-05
  • golang 如何获取map所有key的方式

    golang 如何获取map所有key的方式

    这篇文章主要介绍了golang 获取map所有key的方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • 基于Go语言实现压缩文件处理

    基于Go语言实现压缩文件处理

    在现代的应用开发中,处理压缩文件(如 .zip 格式)是常见的需求,本文将介绍如何使用 Go 语言封装一个 ziputil 包,来处理文件的压缩和解压操作,需要的可以了解下
    2024-11-11

最新评论