ReadTimeout/WriteTimeout 是 MySQL 驱动层 I/O 超时参数,需在 gorm.Open() 后通过 db.DB().SetReadTimeout()/SetWriteTimeout() 显式设置,作用于单次网络读写,与 GORM 的 ConnectTimeout、连接池配置无关。

ReadTimeout/WriteTimeout 是 MySQL 驱动层参数,不是 GORM 层配置
很多人在 gorm.Config 里找 ReadTimeout 字段,找不到就去改 DSN,结果发现没用——因为这两个超时必须通过 MySQL 驱动的 sql.Open 后底层 *sql.DB 设置,GORM 自身不透出该控制权。
它们作用于单次 I/O:比如一次 SELECT 的网络响应耗时、一次 INSERT 的写入发送耗时。和连接池管理(SetConnMaxIdleTime)、建连超时(ConnectTimeout)完全无关。
-
ReadTimeout控制从 socket 读取响应数据的最大等待时间,超时后返回net.ErrTimeout -
WriteTimeout控制向 socket 写入请求数据的最大等待时间,超时后可能已发部分字节(n > 0) - 必须在调用
gorm.Open()后,立刻对db.DB()返回的*sql.DB实例设置 - DSN 中加
readTimeout=5s或writeTimeout=3s仅对某些旧版驱动有效,新版推荐走代码显式设置
正确设置 ReadTimeout 和 WriteTimeout 的步骤
以 MySQL 为例,需在 gorm.Open 成功后,立即操作底层 *sql.DB:
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
<p>sqlDB := db.DB()
sqlDB.SetReadTimeout(10 <em> time.Second) // 注意:这是驱动层读超时
sqlDB.SetWriteTimeout(3 </em> time.Second) // 注意:这是驱动层写超时
sqlDB.SetConnMaxLifetime(5 <em> time.Minute)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetMaxIdleConns(20)
sqlDB.SetConnMaxIdleTime(45 </em> time.Second)
</p>
-
SetReadTimeout和SetWriteTimeout是database/sql在 Go 1.19+ 对 MySQL 驱动的统一支持,不再依赖 DSN 参数 - 值不宜过短(如
100ms),否则正常慢查询会被误杀;也不宜过长(如30s),会拖累 HTTP 请求整体响应 - 若使用 PostgreSQL,对应的是
pgx驱动的Config.ConnConfig.Timeout,而非SetReadTimeout - 务必搭配
db.Ping()验证设置是否生效,失败则 panic,避免静默失效
超时错误必须用 net.Error.Timeout() 判断
当 ReadTimeout 或 WriteTimeout 触发时,错误类型是实现了 net.Error 接口的底层错误,**不会等于 net.ErrTimeout**,直接比较会永远为 false。
- 错误判断必须用类型断言 +
Timeout()方法:if netErr, ok := err.(net.Error); ok && netErr.Timeout() - 不能用
strings.Contains(err.Error(), "timeout"),不同驱动/系统返回文案不一致 - 不能只检查
err != nil就认为是业务失败,要区分超时、连接中断、SQL 语法错等不同原因 - GORM 的
WithContext超时(如context.DeadlineExceeded)和驱动层 I/O 超时是两套机制,可能同时出现
ReadTimeout 和 ConnectTimeout 容易混淆的点
ConnectTimeout 是 GORM gorm.Config 字段,控制建连阶段握手耗时;而 ReadTimeout 是驱动层 I/O 超时,两者生命周期完全不同。
-
ConnectTimeout: 5 * time.Second只影响gorm.Open()这一次建连,成功后即失效 -
SetReadTimeout(10 * time.Second)影响此后所有查询的响应等待,每次Query/Exec都受控 - DSN 中的
timeout=5s是老式 MySQL 驱动参数,已被ConnectTimeout和SetReadTimeout分离替代 - 如果服务部署在高延迟网络(如跨可用区),建议
ConnectTimeout设为 10s,ReadTimeout设为 15s,留出缓冲
实际生效依赖驱动版本和 Go 版本,Go 1.19+ + mysql-driver v1.7+ 组合下行为最稳定;低于此版本可能需要回退到 DSN 参数或手动包装 net.Conn。











