[踩坑]packets.go:428: busy buffer invalid connection
最近在写一个导出数据库数据的小工具,但是发现对于超大表,就会包开头提到的错误。结论就是我们使用的go-sql-driver里面的rows查询类似一个游标,但是mysql中有超时查询时间,这个时间到了 我们使用的rows就失效了,所以就报错了。ps 一般来说 数据库的超时时间我们是无权修改的。
情况一:查询大数据超时
[mysql] 2022/07/01 12:02:04 packets.go:428: busy buffer
invalid connection
invalid connection Rows error.
例如我们查询的数据量比较大的话,可能会耗时比较长。
我们可以先看一下mysql数据库的超时时间:
SHOW VARIABLES LIKE '%timeout%'
connect_timeout | 10 |
---|---|
delayed_insert_timeout | 300 |
have_statement_timeout | YES |
innodb_flush_log_at_timeout | 1 |
innodb_lock_wait_timeout | 20 |
innodb_rollback_on_timeout | OFF |
interactive_timeout | 300 |
lock_wait_timeout | 31536000 |
net_read_timeout | 30 |
net_write_timeout | 60 |
rpl_stop_slave_timeout | 31536000 |
slave_net_timeout | 60 |
wait_timeout | 300 |
connect_time
connect_timeout指的是连接过程中握手的超时时间,即MySQL客户端在尝试与MySQL服务器建立连接时,MySQL服务器返回错误握手协议前等待客户端数据包的最大时限。默认10秒。
interactive_timeout / wait_timeout
MySQL关闭交互/非交互连接前等待的最大时限。默认28800秒。
lock_wait_timeout
sql语句请求元数据锁的最长等待时间,默认为一年。此锁超时对于隐式访问Mysql库中系统表的sql语句无效,但是对于使用select,update语句直接访问MySQL库中标的sql语句有效。
net_read_timeout / net_write_timeout
mysql服务器端等待从客户端读取数据 / 向客户端写入数据的最大时限,默认30秒。
slave_net_timeout
mysql从复制连结等待读取数据的最大时限,默认3600秒。
解决办法:
MySQL doesn't provide safe and efficient canceling mechanism. When context is cancelled or reached readTimeout
, DB.ExecContext
returns without terminating using connection. It cause "invalid connection" next time the connection is used.
MySQL :: MySQL 5.7 Reference Manual :: 8.9.3 Optimizer Hints
MAX_EXECUTION_TIME(N)
Example with a timeout of 1 second (1000 milliseconds):
SELECT /*+ MAX_EXECUTION_TIME(1000) */ * FROM t1 INNER JOIN t2 WHERE ...
情况二:Rows未关闭的情况
首先, Rows 是执行 query 返回的结果,当我们执行 rows, err := tx.Query("SELECT 1")
拿到 Rows 时,数据还在 buffer 里面,并没有读出来。
这时如果有其他协程在这个事务里执行语句,要向 db 发包,就会出现 busy buffer,因为在一个事务里,只有一个连接可以用。
前面提到,把数据从 buffer 中读出来就可以重新利用这一条 mysqlConn 发包,那么把 Rows 中的数据读出来还会出现这个问题吗?是可以的,加上一句 for rows.Next(){rows1.Scan()}
就不会出现 busy buffer 了。
// 来自:go-sql-driver/mysql@1.4.0/rows.go func (rows *textRows) Next(dest []driver.Value) error {if mc := rows.mc; mc != nil {if err := mc.error(); err != nil {return err}// Fetch next row from stream// 这里会调用 mc.readPacket() 将 buffer 里的数据读出来。return rows.readRow(dest)}return io.EOF }
当然关闭也是可以的,我们看一下关闭 rows 后 buffer 会怎样。会由 mysqlConn 来负责处理没有读的 buffer,会调用 mc.readUntilEOF() 将 buffer 里的内容全部读出来,直到 EOF。mc.discardResults() 也会调用 mc.readUntilEOF(),而 mc.readUntilEOF() 则会调用 mc.readPacket()。
// 来自:go-sql-driver/mysql@1.4.0/rows.go func (rows *mysqlRows) Close() (err error) {if f := rows.finish; f != nil {f()rows.finish = nil}mc := rows.mcif mc == nil {return nil}if err := mc.error(); err != nil {return err}// Remove unread packets from streamif !rows.rs.done {err = mc.readUntilEOF()}if err == nil {if err = mc.discardResults(); err != nil {return err}} rows.mc = nilreturn err }
当然了,打开的资源是要关闭的,因此只执行 for rows.Next(){rows1.Scan()}
是不够的,还要关闭 rows.
情况三:为什么不要在一个事务中执行并发的查询?
首先不要用并发的协程去操作同一个连接,实际上上面的分析也说明了,如果你这么做了,go-sql-driver/mysql
很有可能会返回给你一个 busy buffer。
一个事务只有一个连接,当调用 db.Begin()
开启一个事务时,sql.DB
会从连接池中取出一个连接或者创建一个新的连接分配给这个事务。
情况四:可以在一个事务中执行并发的更新吗?
是可以的,因为更新或者插入的操作调用的是 Exec()
,db 返回的 result 在这里就直接从 buffer 中读出来了。
情况五:
mysql 可以最大传输的数据量:
SHOW VARIABLES LIKE 'max_allowed_packet'
Variable_nameValuemax_allowed_packet
1073741824
参考地址:
https://github.blog/2020-05-20-three-bugs-in-the-go-mysql-driver/
[踩坑]packets.go:428: busy buffer invalid connection相关推荐
- gorm踩坑 事务中Row/Rows未关闭导致panic
现象 web服务有个接口,service层开启事务,调用dao层两个接口.发现第二个dao层接口返回Error,在service层事务回滚时panic,该panic无法被recover. 代码详情 事 ...
- SpringBoot踩坑记录 Invalid bound statement (not found)引发的一些列问题
SpringBoot踩坑记录 Invalid bound statement (not found)引发的一些列问题 当你开开心心搭建了一个SpringBoot项目,用插件生成了entity.dao. ...
- 微信分享踩坑:config:invalid signature错误的解决方法
微信分享踩坑:config:invalid signature错误的解决方法 一般出现这个错误多半是签名获取失败,而我根据我获取到的签名跟签名算法校验里面得到的签名是一样的,于是查找大量文档,核实可能 ...
- SpringBoot踩坑记录--Invalid bound statement (not found): com.zxq.crud.dao.UserDao.selectAllByDepart
SpringBoot踩坑记录--Invalid bound statement: com.zxq.crud.dao.UserDao.selectAllByDepart 运行SpringBoot项目时提 ...
- OpenDDS踩坑(2)-DCPSInfoRepo ERROR add_domain_participant returned invalid id
OpenDDS踩坑(2)-DCPSInfoRepo add_domain_participant returned invalid id 本文针对OpenDDS新手处理无法正常运行测试项目问题. 测试 ...
- centos 8 使用 nmcli 配置网桥Bridge(最后有踩坑过程)
文章最后有踩坑过程,前面先写正常流程. 背景:最近想在自己笔记本上搭建openstack集群,再在集群上面上面跑K8S. 首先需要准备两个网络供虚拟机使用,一个网络用于连接互联网用来在线安装各种服务和 ...
- k8s containerd集群配置安装完整踩坑教程
完整踩坑和精简内容 k8s containerd配置 containerd安装参考 k8s安装参考 环境 两台机器 hostnamectl set-hostname master hostnamect ...
- Go 语言踩坑记——panic 与 recover
题记 Go 语言自发布以来,一直以高性能.高并发著称.因为标准库提供了 http 包,即使刚学不久的程序员,也能轻松写出 http 服务程序. 不过,任何事情都有两面性.一门语言,有它值得骄傲的优点, ...
- 小程序统一服务消息_[miniblog]小程序订阅消息踩坑记
有阵子没有更新我的mini-blog了,这次把推送消息那块做了些改动,小程序的模板消息即将废弃,订阅消息终于来了. 关于订阅消息 订阅消息分为一次性订阅和长期订阅,长期订阅就不说啦,不是个人号可以染指 ...
最新文章
- centos 添加中文输入法
- struts导入Excel进行解析
- war 发布后页面不更新_一文看懂tomcat8如何配置web页面管理
- JavaScrip调用腾讯地图
- html表单php比较三个值大小,PHP比较三个数大小实现办法
- 虚拟机中使用Samba实现文件共享,并在win10上创建映射网络驱动器
- 列出C#进程以及详细信息
- linux bash环境,Win10系统怎样启用Linux Bash环境
- 字段连接select语句
- anaconda安装PIL库报错:PIL库不存在的解决方法
- Android studio Mac 版上传代码提示The subversion command line tools are no longer provided by Xcode
- 苹果“噩梦”来袭!iPhone 13、iPad竟遭遇停产 十多年来首次
- CDN 的诞生、术语、原理、特征以及应用场景
- 区块链:5、匿名性和隐私性
- “终于懂了” 系列,安卓工程师的面试题
- 中国城市乞丐的五大经典表情
- 拼多多按关键字搜索商品 API
- CSDN博客中删除空白代码块
- 用python监控A股股票波动并发送预警邮件_V3
- 全国计算机等级二级C语言上机编程题题型