一篇文章彻底理解数据库的各种 JDBC 超时参数 2

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 一篇文章彻底理解数据库的各种 JDBC 超时参数

6 套接字超时的含义是什么?

数据库连接的套接字超时,即 socket timeout, 具体又包括登录超时 (loginTimeout),网络超时/连接超时 (connectTimeout/NetworkTimeout),和常规的套接字超时 socket timeout,各自的含义如下。

6.1 登录超时 loginTimeout

登录超时,即 loginTimeout,是数据库用户成功登录到数据库服务器的超时时间。

  • JDBC 标准 API 中定义了登录超时的含义,如java.sql.DriverManager#setLoginTimeout,javax.sql.CommonDataSource#setLoginTimeout;

640.png640.png

6.2 连接超时

连接超时,即 connectTimeout,有时也被称为 网络超时 NetworkTimeout,是驱动程序建立 JDBC 底层的 TCP 连接的超时时间。

  • JDBC 标准 API 中定义了该超时时间的含义,如 java.sql.Connection#setNetworkTimeout:

640.png


6.3 常规的套接字超时

常规的套接字超时,即 socket timeout, 其含义如下:

  • 套接字连接建立后,对 socket 中数据的读写操作都是阻塞的(涉及到 CPU 用户态和内核态的切换以及系统调用),套接字超时即是读写 socket 底层数据时的阻塞超时时间;
  • 调用 Socket.write()对 socket 进行写操作时,应用通过系统调用将数据传给本地操作系统内核的缓冲区之后就可以立即返回(控制权立即回到应用上),通过网络对底层数据进行远程传输的操作是由操作系统进行的,所以一般应用代码的 socket 写操作很快就会返回,一般不会发生长时间的阻塞(当然如果系统内核缓冲区由于网络故障满了的话,Socket.write()也会进入waiting阻塞状态,此时操作系统会尝试重新发包,当达到重试的次数时就会产生系统异常错误);
  • 调用 Socket.read() 对 socket 进行读操作时,由于首先需要通过网络将 socket 底层的远程数据传输到本地,然后才能经由操作系统将底层数据返回给用户态的应用程序,所以一般应用代码的 socket 读操作会消耗一段时间,可能会因为尝长时间的阻塞而发生超时异常;
  • 在网络连接发生异常或服务器异常崩溃宕机时,因为 TCP/IP 的工作机制, socket 无法检测到底层网络的异常,因此应用系统也就无法检测到跟 DBMS 之间的 TCP 连接是否处于断开状态,所以应用端如果没有配置套接字超时,应用就会无期限地等待 DMBS的返回结果(这种连接也被称为死亡连接或僵尸连接 "dead connection.") ,为了避免这种僵尸连接,同样需要配置套接字超时;

6.4 登录超时,连接超时,常规套接字超时的区别与联系

登录超时,连接超时,常规的套接字超时,三者的区别与联系如下:

  • 登录超时是高级别的数据库服务层面的超时,而连接超时和套接字超时是低级别的socket层面的超时;
  • 由于用户登录数据库服务器时,底层包含了 和数据库服务器之间的 tcp 连接的建立,也包含了数据库服务器对用户的认证,所以一般需要配置登录超时 > 连接超时;
  • 登录超时和连接超时 只影响客户端和数据库服务器之间的连接的初始建立,而套接字超时 会影响客户端和服务器之间的连接的整个生命周期,包括初始连接的建立,也包括连接建立完毕后所有SQL语句的执行(有些SQL可能需要耗费较长时间),所以一般需要配置套接字超时 > 登录超时,套接字超时 > 连接超时;
- The loginTimeout specifies how long the whole process of logging into the database is allowed to take. It governs the operation of connecting and authenticating to the dbms server, this involves establishing a TCP connection followed by one or more exchanges of packets for the handshake and authentication to the dbms server;
- The connectTimeout specifies how long to wait for a TCP network connection to get established, it governs the time needed to establish a TCP socket connection, and as establishing a TCP connection is part of establishing a database connection and doesn't guarantee a login, so loginTimeout >= connectTimeout;
- The The socketTimeout specifies how long the client will wait for a response to a command from the server before throwing an error, it governs the time a socket can be blocked waiting to read from a socket, this involves all reads from the server, not just during connect, but also during subsequent interaction with the server (eg executing queries),so you may want to set it higher (eg for other operations that take a long time to get a response back) than you are willing to wait for the login to complete;
- A socketTimeout can be used as both a brute force global query timeout and a method of detecting network problems;
- the loginTimeout and connectTimeout are related to establishing a connection, while socketTimeout is relevant for the whole database session;
- connectTimeout and socketTimeout are timeouts on low-level socket operations, while loginTimeout is on a high level - the database level;
- Generally, the application hangs from network issues when the application is calling Socket.read(). However, depending on the network composition or the error type, it can rarely be in waiting status while running Socket.write(). When the application calls Socket.write(), the data is recorded to the OS kernel buffer and then the right to control is returned to the application immediately. Thus, as long as a valid value is recorded to the kernel buffer, Socket.write() is always successful. However, if the OS kernel buffer is full due to a special network error, even Socket.write() can be put into waiting status;

7 查询超时和套接字超时有何关系?

我们经常遇到开发同学抱怨,明明对某个SQL语句配置了查询超时,但看起来查询超时就是不生效,其实这种情况是因为底层的网络出了问题,而查询超时机制在网络异常的状况下是不生效的,其原因如下:

  • 高层次的异常依赖于低层次的异常,只有在低层次的异常机制正常工作的前提下,高层次的异常机制才能正常工作,所以事务超时和查询超时的正常工作,都依赖于套接字超时的正常运转;
  • 查询超时不能用来解决网络异常状况下的超时问题,查询超时仅仅只能用来限制某个语句的执行时间;
  • 为应对网络连接的异常或数据库管理系统的异常宕机,需要使用数据库驱动的套接字超时;
  • 一般不推荐通过套接字超时限制sql语句的执行时间,套接字超时一般需要配置为比查询超时大一些 (如果套接字超时小于查询超时,此时由于先触发套接字超时的处理,查询超时的处理逻辑也就不会被执行了,查询超时也就失去了意义);
- The higher level timeout is dependent on the lower level timeout. The higher level timeout will operate normally only if the lower level timeout operates normally as well. If the JDBC driver socket timeout does not work properly, then higher level timeouts such as statement timeout and transaction timeout will not work properly either.
- The statement timeout does not handle the timeouts at the time of network failure, it does only one thing: restricts the operation time of 1 statement,and handling timeout to prevent network failure must be done by JDBC Driver;
- Socket timeout value for JDBC driver is necessary when the DBMS is terminated abruptly or an network error has occured (equipment malfunction, etc.). 
- Because of the structure of TCP/IP, there are no means for the socket to detect network errors. Therefore, the application cannot detect any disconnection with the DBMS. If the socket timeout is not configured, then the application may wait for the results from the DBMS indefinitely. (This connection is also called a "dead connection."),to prevent dead connections, a timeout must be configured for the socket.
- Socket timeout can be configured via JDBC driver. By setting up the socket timeout, you can prevent the infinite waiting situation when there is a network error and shorten the failure time.
- It is not recommended to use the socket timeout value to limit the statement execution time. So the socket timeout value must be higher than the statement timeout value.
- If the socket timeout value is smaller than the statement timeout value, as the socket timeout will be executed first, and the statement timeout value becomes meaningless and will not be executed.

8 如何配置常见数据库的套接字超时?

  • 如上文所说,为应对网络连接的异常以及数据库管理系统的崩溃宕机,需要使用数据库驱动的套接字超时;
  • 套接字超时在底层又分为创建连接的超时和读写数据的超时两种,究其原因,是由 TCP 的工作机制决定的,包括连接建立的机制以及连接建立完毕后数据传输的机制;
  • 套接字的连接超时和读写超时,在JAVA源码层面,分别对应方法 Socket.connect(SocketAddress endpoint, int timeout) 和方法 Socket.setSoTimeout(int timeout):

640.png640.png

  • 绝大多数数据库驱动都支持对上述两种超时的配置,虽然不同数据库驱动具体的配置方式略有不同,但在驱动代码的最底层都是调用的方法 Socket.connect(SocketAddress endpoint, int timeout) 和方法 Socket.setSoTimeout(int timeout);

下面总结下常见数据库中,套接字连接超时和读写超时的配置方式:

  • mysql 可以通过url参数指定套接字的连接超时和读写超时,超时单位是毫秒,如:jdbc:mysql://localhost:3306/ag_admin?useUnicode=true&characterEncoding=UTF8&connectTimeout=60000&socketTimeout=60000
  • pg 也可以通过url参数指定套接字的连接超时和读写超时,不过超时单位是秒:jdbc:postgresql://localhost/test?user=fred&password=secret&&connectTimeout=60&socketTimeout=60
  • oracle 的 thin jdbc driver 不支持通过 URL 参数指定套接字的连接超时和读写超时,而是需要通过系统参数 oracle.net.CONNECT_TIMEOUT 和 oracle.jdbc.ReadTimeout 来分别指定,这两个参数的单位都是毫秒,默认值都是0,(读写超时参数,在 10.1.0.5 以下版本的驱动中是 oracle.net.READ_TIMEOUT,在 10.1.0.5 以上的版本中才是 oracle.jdbc.ReadTimeout),比如可以通过 OracleDatasource.setConnectionProperties(java.util.Properties prop) 指定,使用 DBCP 时可以通过 BasicDatasource.setConnectionProperties(java.util.Properties prop)或 BasicDatasource.addConnectionProperties(java.util.Properties prop)指定;


640.png640.png


# 配置参数
final static String url= "jdbc:oracle:thin:@myhost:1521/myorcldbservicename";
final static String user = "hr";
final static String password = "hr";
final static String CONNECT_TIMEOUT = "20000";
final static String READ_TIMEOUT = "50000";
# 使用 DataSource 获取连接
Properties connectionProperties = new Properties(); 
connectionProperties.put(“oracle.net.CONNECT_TIMEOUT”, CONNECT_TIMEOUT);
connectionProperties.put(“oracle.jdbc.ReadTimeout”, READ_TIMEOUT);
OracleDataSource ods = new OracleDataSource();
ods.setURL(url); 
ods.setUser(user); 
ods.setPassword(password);    
ods.setConnectionProperties(connectionProperties);
# 使用 DriverManager 获取连接
Class<?> oracleDriverClass = Class.forName("oracle.jdbc.driver.OracleDriver");
Properties connectionProperties = new Properties(); 
connectionProperties.put(“oracle.net.CONNECT_TIMEOUT”, CONNECT_TIMEOUT);
connectionProperties.put(“oracle.jdbc.ReadTimeout”, READ_TIMEOUT);  
//也可以通过环境变量/系统参数设置,注意需要在 connection 连接之前设置
//System.setProperty("oracle.net.CONNECT_TIMEOUT", connectTimeout);
//System.setProperty("oracle.jdbc.ReadTimeout", readTimeout); 
connectionProperties.put(“user”, user);
connectionProperties.put(“password”, password);  
Connection con=DriverManager.getConnection(url, props);

9 操作系统级别的套接字超时检测机制

除了以上几个数据库的超时参数,还需要注意,应用程序和数据库所在的服务器也可以配置操作系统级别的套接字超时检测。

  • 当应用系统没有指定数据库的连接超时和套接字超时时,应用系统大部分情况下都不能有效检测到网络故障。因此,当网络错误发生后,在应用系统成功重新建立连接前或成功读取到数据前,应用系统都会无限制地一直处于等待状态;
  • 为避免上述状况,运维人员可以在服务器上配置套接字超时检测,从而在服务器的操作系统层面主动对网络连接进行校验;
  • 比如在 linux 服务器上将 KeepAlive 的检测间隔配置为30分钟后,在遇到网络问题时,即使应用系统没有在 JDBC 数据库驱动中指定套接字超时(或指定为0),因为网络问题造成的数据库连接问题的持续时间也不会超过30分钟;
  • linux下,操作系统级别的套接字超时检测机制,主要跟以下几个内核参数相关:
  • /proc/sys/net/ipv4/tcp_keepalive_intvl: 默认 75秒,The number of seconds between TCP keep-alive probes;
  • /proc/sys/net/ipv4/tcp_keepalive_probes: 默认 9 次,The maximum number of TCP keep-alive probes to send before giving up and killing the connection if no response is obtained from the other end;
  • /proc/sys/net/ipv4/tcp_keepalive_time: 默认 7200 秒即2小时,The number of seconds a connection needs to be idle before TCP begins sending out keep-alive probes. Keep-alives are sent only when the SO_KEEPALIVE socket option is enabled. An idle connection is terminated after approximately an additional 11 minutes (9 probes an interval of 75 seconds apart) when keep-alive is enabled;
  • linux下,可以通过 sysctl 命令查看和更改上述内核参数;
# 查询内核参数
- sysctl -a  //显示当前所有可用的内核参数
- sysctl net.ipv4.tcp_keepalive_time //查询某个内核参数
- cat /proc/sys/net/ipv4/tcp_keepalive_time //查询某个内核参数
#修改内核参数
- sysctl net.ipv4.tcp_keepalive_time=3600//修改某个内核参数
- vim /etc/sysctl.conf//在配置文件中修改内核参数
- sysctl  -p  //从配置文件 sysctl.conf 中重新加载内核参数 
- If the socket timeout or the connect timeout is not configured, most of the time, applications cannot detect network errors. So, until the applications are connected or are able to read data, they will wait indefinitely. 
- To prevent this, we can configure a socket timeout time at the OS level, so the Linux servers can check the network connection at the OS level.
- If you set the KeepAlive checking cycle for the Linux servers to 30 minutes, then even if someone set the JDBC driver‘s socket timeout to 0, which means no timeout, the DBMS network connection problems caused by network issues do not surpass 30 minutes/The JDBC connection hang recovers 30 minutes after the network connection failure, that is to say, the JDBC driver's socket timeout is affected by the OS's socket timeout configuration. 
- Generally, the application hangs from network issues when the application is calling Socket.read(). However, depending on the network composition or the error type, it can rarely be in waiting status while running Socket.write(). When the application calls Socket.write(), the data is recorded to the OS kernel buffer and then the right to control is returned to the application immediately. Thus, as long as a valid value is recorded to the kernel buffer, Socket.write() is always successful. However, if the OS kernel buffer is full due to a special network error, even Socket.write() can be put into waiting status. In this case, the OS tries to resend the packet for a certain amount of time, and generates an error when it reaches the limit.

10 相关源码与参考连接

# JDBC API 相关类与方法
java.sql.DriverManager#setLoginTimeout
javax.sql.CommonDataSource#setLoginTimeout
java.sql.Connection#getNetworkTimeout
java.sql.Connection#setNetworkTimeout
java.sql.Statement#setQueryTimeout
# oracle JDBC driver 相关类与方法
oracle.jdbc.OracleDriver
oracle.jdbc.pool.OracleDataSource#setLoginTimeout
oracle.jdbc.OracleConnection
oracle.jdbc.OracleConnection#CONNECTION_PROPERTY_THIN_READ_TIMEOUT
oracle.jdbc.OracleConnection#CONNECTION_PROPERTY_THIN_NET_CONNECT_TIMEOUT。
oracle.jdbc.OracleConnectionWrapper#setNetworkTimeout
oracle.jdbc.driver.PhysicalConnection#setNetworkTimeout
oracle.jdbc.driver.OracleStatement#setQueryTimeout
oracle.jdbc.driver.OracleStatement#doExecuteWithTimeout
oracle.jdbc.driver.OraclePreparedStatement#executeForRowsWithTimeout
oracle.jdbc.driver.OracleTimeoutPollingThread
# mysql JDBC driver 相关类与方法
com.mysql.cj.jdbc.Driver
com.mysql.cj.jdbc.MysqlDataSource#setLoginTimeout
com.mysql.cj.jdbc.ConnectionImpl#setNetworkTimeout
com.mysql.cj.jdbc.ConnectionWrapper#setNetworkTimeout
com.mysql.cj.jdbc.StatementImpl#setQueryTimeout
com.mysql.cj.jdbc.StatementWrapper#setQueryTimeout
#参考链接
- https://www.cubrid.org/blog/3826470


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
Java 关系型数据库 数据库连接
JDBC:Java与数据库的“黄金搭档”,为何它如此重要?
JDBC:Java与数据库的“黄金搭档”,为何它如此重要?
47 8
|
9天前
|
SQL druid 数据库
如何进行数据库连接池的参数优化?
数据库连接池参数优化包括:1) 确定合适的初始连接数,考虑数据库规模和应用需求;2) 调整最大连接数,依据并发量和资源状况;3) 设置最小空闲连接数,平衡资源利用和响应速度;4) 优化连接超时时间,确保系统响应和资源利用合理;5) 配置连接有效性检测,定期检查连接状态;6) 调整空闲连接回收时间,适应访问模式并配合数据库超时设置。
|
13天前
|
缓存 监控 关系型数据库
如何根据监控结果调整 MySQL 数据库的参数以提高性能?
【10月更文挑战第28天】根据MySQL数据库的监控结果来调整参数以提高性能,需要综合考虑多个方面的因素
53 1
|
26天前
|
监控 数据库 索引
避免锁等待超时对数据库性能的影响
【10月更文挑战第16天】避免锁等待超时对数据库性能的影响需要综合考虑多个方面,通过不断地优化和改进,来提高数据库的并发处理能力和稳定性。
35 1
|
2月前
|
存储 SQL 关系型数据库
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
MySQL如何进行分库分表、数据迁移?从相关概念、使用场景、拆分方式、分表字段选择、数据一致性校验等角度阐述MySQL数据库的分库分表方案。
397 15
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
|
1月前
|
SQL 数据管理 数据库
文章初学者指南:SQL新建数据库详细步骤与最佳实践
引言:在当今数字化的世界,数据库管理已经成为信息技术领域中不可或缺的一部分。作为广泛使用的数据库管理系统,SQL已经成为数据管理和信息检索的标准语言。本文将详细介绍如何使用SQL新建数据库,包括准备工作、具体步骤和最佳实践,帮助初学者快速上手。一、准备工作在开始新建数据库之前,你需要做好以下准备工作
117 3
|
1月前
|
SQL Java 数据库
Springboot+spring-boot-starter-data-jdbc实现数据库的操作
本文介绍了如何使用Spring Boot的spring-boot-starter-data-jdbc依赖来操作数据库,包括添加依赖、配置数据库信息和编写基于JdbcTemplate的数据访问代码。
46 2
|
1月前
|
SQL 关系型数据库 MySQL
数据库:MYSQL参数max_allowed_packet 介绍
数据库:MYSQL参数max_allowed_packet 介绍
58 2
|
2月前
|
SQL 关系型数据库 数据库连接
php连接数据库之PDO,PDO的简单使用和预定义占位符的使用以及PDOStatement对象的使用,占位符的不同形式,bindValue和bindParam绑定预定义占位符参数的区别
本文介绍了PHP中PDO(PHP Data Objects)扩展的基本概念和使用方法。内容包括PDO类和PDOStatement类的介绍,PDO的简单使用,预定义占位符的使用方法,以及PDOStatement对象的使用。文章还讨论了绑定预定义占位符参数的不同形式,即bindValue和bindParam的区别。通过具体示例,展示了如何使用PDO进行数据库连接、数据查询、数据插入等操作。
php连接数据库之PDO,PDO的简单使用和预定义占位符的使用以及PDOStatement对象的使用,占位符的不同形式,bindValue和bindParam绑定预定义占位符参数的区别
|
1月前
|
SQL druid Java
JDBC和数据库连接池-两个工具类-JDBCUtilsByDruid和BasicDAO
JDBC和数据库连接池-两个工具类-JDBCUtilsByDruid和BasicDAO
28 0