最近在写一个导出数据库数据的小工具,但是发现对于超大表,就会包开头提到的错误。结论就是我们使用的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相关推荐

  1. gorm踩坑 事务中Row/Rows未关闭导致panic

    现象 web服务有个接口,service层开启事务,调用dao层两个接口.发现第二个dao层接口返回Error,在service层事务回滚时panic,该panic无法被recover. 代码详情 事 ...

  2. SpringBoot踩坑记录 Invalid bound statement (not found)引发的一些列问题

    SpringBoot踩坑记录 Invalid bound statement (not found)引发的一些列问题 当你开开心心搭建了一个SpringBoot项目,用插件生成了entity.dao. ...

  3. 微信分享踩坑:config:invalid signature错误的解决方法

    微信分享踩坑:config:invalid signature错误的解决方法 一般出现这个错误多半是签名获取失败,而我根据我获取到的签名跟签名算法校验里面得到的签名是一样的,于是查找大量文档,核实可能 ...

  4. SpringBoot踩坑记录--Invalid bound statement (not found): com.zxq.crud.dao.UserDao.selectAllByDepart

    SpringBoot踩坑记录--Invalid bound statement: com.zxq.crud.dao.UserDao.selectAllByDepart 运行SpringBoot项目时提 ...

  5. OpenDDS踩坑(2)-DCPSInfoRepo ERROR add_domain_participant returned invalid id

    OpenDDS踩坑(2)-DCPSInfoRepo add_domain_participant returned invalid id 本文针对OpenDDS新手处理无法正常运行测试项目问题. 测试 ...

  6. centos 8 使用 nmcli 配置网桥Bridge(最后有踩坑过程)

    文章最后有踩坑过程,前面先写正常流程. 背景:最近想在自己笔记本上搭建openstack集群,再在集群上面上面跑K8S. 首先需要准备两个网络供虚拟机使用,一个网络用于连接互联网用来在线安装各种服务和 ...

  7. k8s containerd集群配置安装完整踩坑教程

    完整踩坑和精简内容 k8s containerd配置 containerd安装参考 k8s安装参考 环境 两台机器 hostnamectl set-hostname master hostnamect ...

  8. Go 语言踩坑记——panic 与 recover

    题记 Go 语言自发布以来,一直以高性能.高并发著称.因为标准库提供了 http 包,即使刚学不久的程序员,也能轻松写出 http 服务程序. 不过,任何事情都有两面性.一门语言,有它值得骄傲的优点, ...

  9. 小程序统一服务消息_[miniblog]小程序订阅消息踩坑记

    有阵子没有更新我的mini-blog了,这次把推送消息那块做了些改动,小程序的模板消息即将废弃,订阅消息终于来了. 关于订阅消息 订阅消息分为一次性订阅和长期订阅,长期订阅就不说啦,不是个人号可以染指 ...

最新文章

  1. centos 添加中文输入法
  2. struts导入Excel进行解析
  3. war 发布后页面不更新_一文看懂tomcat8如何配置web页面管理
  4. JavaScrip调用腾讯地图
  5. html表单php比较三个值大小,PHP比较三个数大小实现办法
  6. 虚拟机中使用Samba实现文件共享,并在win10上创建映射网络驱动器
  7. 列出C#进程以及详细信息
  8. linux bash环境,Win10系统怎样启用Linux Bash环境
  9. 字段连接select语句
  10. anaconda安装PIL库报错:PIL库不存在的解决方法
  11. Android studio Mac 版上传代码提示The subversion command line tools are no longer provided by Xcode
  12. 苹果“噩梦”来袭!iPhone 13、iPad竟遭遇停产 十多年来首次
  13. CDN 的诞生、术语、原理、特征以及应用场景
  14. 区块链:5、匿名性和隐私性
  15. “终于懂了” 系列,安卓工程师的面试题
  16. 中国城市乞丐的五大经典表情
  17. 拼多多按关键字搜索商品 API
  18. CSDN博客中删除空白代码块
  19. 用python监控A股股票波动并发送预警邮件_V3
  20. 全国计算机等级二级C语言上机编程题题型

热门文章

  1. 【Apple Music如何开通学生会员:使用学校邮箱辅助验证】
  2. 简易聊天室代码分享 js+socket.io
  3. Lumerical官方案例、FDTD时域有限差分法仿真学习(十七)——Y分支功分器
  4. Ubuntu16.04+Kinect2摄像头进行物体识别
  5. 数据库SQL(二):View(视图)详细
  6. 国产银河麒麟系统源码安装Openvas
  7. 字节码是什么?字节码增强有哪些?
  8. 565 数组嵌套(图论思想-求解所有环的最大长度)
  9. Git--SSH登录
  10. 2023NPDP产品经理认证如何考取?