
上面代码可以说明,连接池已经提供了完备的机制来处理连接错误,从连接池中取出的连接如果失效时会自动重试,必要时会直接创建新的连接,来保证sql请求不会因为连接失效而响应失败。
为此专门进行了对比验证,将sqlproxy改为连接到mysql,看是否存在此问题。


对应打印此日志的相关代码位置:
这个driver.ErrBadConn是go官方SDK定义的,上文提到,database/sql包的连接池通过检测此错误来处理失效连接并自动重试。
而前面连接达梦时我们获取到的错误信息为:,并不是go官方database/sql所定义的driver.ErrBadConn.
由此可以基本判断,是达梦驱动在遇到连接问题时未按照标准的driver.ErrBadConn返回而导致。
解法1:sqlproxy主动检测失效连接,开一个定时器,通过扫描来监听db实例的连接状态,发现异常主动重连。代码大概如下所示:

- 优点:不依赖于具体驱动的实现。
- 缺点:在database/sql连接池已经提供了一种方法机制的基础上,这样做明显有些功能冗余。而且每个db实例都需要单独来扫,有一定有开销。
解法2:修改dm驱动。将dm驱动中相关API函数返回的统一改为driver.ErrBadConn再返回。
- 优点:和go官方解决此问题的方法对齐,更加合理。
- 缺点:dm驱动变成了定制,会给后续更新dm驱动带来不便。
我们还是倾向于更合理的解决方法,选择了方法2,至于相应的弊端,准备在达梦社区提交一个issue争取让达梦团队也配合修改。
由于dm驱动代码是混淆过的,我们难以确认communication error这个错误在其它地方是否有特殊用途,如果直接从定义的地方替换这个错误就会有风险。
比较稳妥的做法是在驱动对外公开的所有API方法中都替换下这个错误,虽然改动量多一些,但结果可控。具体做法为:
- 定义一个replaceError函数,如果是网络连接类错误就替换成标准的driver.ErrBadConn。
对于以下公开的API方法,都在返回err前替换错误码:
- Query 和 QueryContext
- Exec 和 ExecContext
- Prepare 和 PrepareContext
- Ping
- Begin 和 BeginTx
- Commit
- Rollback
代码改动示例如下:
运行后,在非事务场景下运行正常,在事务场景下偶现这个错误:

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/192583.html