深入理解数据库编程中的超时设置

作者: admin 分类: 公众号存档            0 次浏览 发布时间: 2021-08-10 23:49

【转载声明】本文为转载文章,原作者「田守枝」,版权归原作者所有。 原文链接:https://mp.weixin.qq.com/s/qQSIPMM_-NGXgaX3V4-oEQ

公众号:杨建荣的学习笔记 · 作者:田守枝 · 发布:2021-08-10 23:49:21 · 原文链接

点击上方”田守枝的技术博客”,关注我

数据库是开发过程中最常用的组件,然而我们经常会遇到各种各样的超时异常,如:

  • connect timeout:建立数据库连接超时

  • socket timeout:socket读取超时

  • statement timeout:单个sql执行超时

  • transaction timeout:事务执行超时,一个事务中可能包含多个sql

  • get connection timeout:从连接池中获取链接超时

读完此文,你将彻底掌握各种超时产生的根本原因,以及对应的解决方案。

1 connectTimeout与socketTimeout

connect timeout和socket timeout都属于TCP层面的超时。

以mysql为例,我们可以在jdbc url中指定connectTimeout和socketTimeout。如:

jdbc:mysql://localhost:3306/db?connectTimeout=1000&socketTimeout=60000

     其中:

  • connectTimeout:表示的是数据库驱动(mysql-connector-java)与mysql服务器建立TCP连接的超时时间。

  • socketTimeout:是通过TCP连接发送数据(在这里就是要执行的sql)后,等待响应的超时时间。

mysql驱动(mysql-connector-java)在与服务端建立Socket连接时,会将这两个参数设置到socket对象上参见:

com.mysql.jdbc.MysqlIO类的构造方法:

提示:这里的mysqlConnection类型为java.net.Socket  

如果这两个参数设置的不够合理,都会导致mysql驱动抛出以下异常:

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure  

    相信大部分读者对这个异常都不陌生。接下来笔者将分别演示这两个异常是如何产生的,并提出对应的解决方案。

1.1 connectTimeout

下面首先通过一个案例演示如何模拟connectTimeout

@Testpublic void testConnectTimeout() throws SQLException {    DruidDataSource dataSource = new DruidDataSource();    dataSource.setInitialSize(5);    dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test?connectTimeout=5");    dataSource.setUsername("root");    dataSource.setPassword(“your password");    dataSource.setDriverClassName("com.mysql.jdbc.Driver”);    dataSource.init();//初始化,底层通过mysql-connector-java建立数据库连接}

笔者这里将connectTimeout设置为了5ms,表示mysql驱动与服务端建立一个连接最多不能超过5ms。由于这里是与本地(127.0.0.1)数据库建立一个连接,5ms已经足够。然而,如果你是与一个远程数据库建立连接,那么5ms可能无法完成建立一个连接,此时你极有可能会遇到类似以下异常:

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failureThe last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)    ...Caused by: java.net.SocketTimeoutException: connect timed out    at java.net.PlainSocketImpl.socketConnect(Native Method)    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)    ...

到这里,我们看到了:

CommunicationsException异常,异常的Caused by部分是

java.net.SocketTimeoutException: connect timed out

        也就是说,建立底层socket 连接超时了。这通常意味着我们需要将connectTimeout值调大。

        这个问题并非无关紧要,特别是在公司有多个数据中心的情况下,尤其需要注意。笔者曾经遇到过有业务开发同学,应用部署在北京,数据库集群在北京和上海都有部署,如下图:

admin

杨建荣,《Oracle DBA工作笔记》《MySQL DBA工作笔记》作者,dbaplus社群发起人之一,腾讯云TVP,现任竞技世界系统部经理,拥有十多年数据库开发和运维经验,目前专注于开源技术、运维自动化和性能调优

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注