Spring Boot使用tomcat连接池时出现的:Connection reset by peer: socket write error

Spring Boot在1.x.x版本默认使用tomcat连接池,该连接池配置不当时,容易出现如下问题

Connection reset by peer: socket write error

或者

The last packet successfully received from the server was xxx milliseconds ago. 
The last packet sent successfully to the server was xxxx milliseconds ago.

自2.0.0版后Spring Boot默认连接池改为HikariCP

出现该异常原因:tomcat连接池testWhileIdle属性默认为false,连接闲置时,并未进行验证,当数据库连接不稳定(网络波动,短暂断网)或者长时间不用连接超时(mysql默认连接8小时未用则超时),池中保有的连接其实已经断开,但由于没有检查,连接池还是认为当前连接可用,当程序调用数据库时,就会抛出异常

解决方案:

解决方法的主题思路是:设置testOnBorrow=true,即当从连接池取连接时先检验连接是否有效

1. 使用spring boot默认配置情况下,一般不会出现该问题(spring自动帮我们设置了tomcat连接池的相关属性),如需定制,使用

spring.datasource.tomcat.*=

tomcat后面配置tomcat连接池中的各种属性,如

spring.datasource.tomcat.testOnBorrow=true
spring.datasource.tomcat.validationQuery=SELECT 1

2. 当自己配置DataSource时,该bug在1.x.x版本为必现bug

  • application.properties
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driverClassName=com.mysql.jdbc.Driver
  • DataSourceConfig.java
@Configuration
public class DataSourceConfig {
	
	
	@Bean
	@Primary
	@ConfigurationProperties("spring.datasource")
	public DataSource dataSource() {
	    return DataSourceBuilder.create().build();
	}
	
}

按照上述配置完成后,最终得到的DataSource里tomcat连接池的配置全是默认值(和spring自动配置时不同),默认情况下tomcat连接池的所有test属性都是false,连接在产生后就不会再进行检测,当我们切断网络,再重连后,连接池中所有连接失效,并且不会自动重连,程序使用连接时抛出异常,该bug极容易被忽略,因为一般情况下不会复现(生产环境网络稳定),唯一可能会暴露该bug的,是数据库的wait_timeout时间(mysql为例),当一个连接8小时未使用时,数据库会自动断开,这时连接池中该连接已经失效,可由于没有验证机制,导致抛出异常,具体表现,应用运行8小时后,会有数据库连接异常报错,甚至如果8小时都没有使用过,会出现根本用不了的情况

修复方法:

  • application.properties
#这里以配置两个数据库为例,该配置仅适用于1.x.x,以tomcat为默认连接池的版本
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driverClassName=com.mysql.jdbc.Driver

#重点,注意这里不加tomcat
spring.datasource.testOnBorrow=true
spring.datasource.validationQuery=SELECT 1

datasource.datacenter.url=jdbc:sqlserver://127.0.0.1:3306;DatabaseName=test
datasource.datacenter.username=root
datasource.datacenter.password=root
datasource.datacenter.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver

datasource.datacenter.testOnBorrow=true
datasource.datacenter.validationQuery=SELECT 1
  • DataSourceConfig
@Configuration
public class DataSourceConfig {	
	
	@Bean
	@Primary
	@ConfigurationProperties("spring.datasource")
	public DataSource dataSource() {
	    return DataSourceBuilder.create().build();
	}	
	
	@Bean
	@ConfigurationProperties("datasource.datacenter")
	public DataSource dataCenterDataSource() {
		return DataSourceBuilder.create().build();
	}
}

补充:

DataSourceBuilder在create()的时候,仅仅创建了一个空的DataSourceBuilder

public static DataSourceBuilder create() {
	return new DataSourceBuilder(null);
}

该空DataSourceBuilder在build方法

	public DataSource build() {
		Class<? extends DataSource> type = getType();
		DataSource result = BeanUtils.instantiate(type);
		maybeGetDriverClassName();
		bind(result);
		return result;
	}

getType()方法返回具体使用哪个连接池,如果我们配置了,就使用配置的,如果没有配置,spring会按顺序判断可用的连接池

private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
			"org.apache.tomcat.jdbc.pool.DataSource",
			"com.zaxxer.hikari.HikariDataSource",
			"org.apache.commons.dbcp.BasicDataSource", // deprecated
			"org.apache.commons.dbcp2.BasicDataSource" };

当然这是1.x.x版本,拿到具体连接池DataSource的Class后,用BeanUtils.instantiate(type)把该类实例化,后两行为绑定配置信息,当然这里由于我们构建的是个空的DataSourceBuilder,bind的各种属性自然都是空,包括数据库的连接信息,总之到这一步,return的result,除了明确了使用那个连接池,其他配置信息都是空,之后在放入spring容器时,spring会根据@ConfigurationProperties("spring.datasource"),对该类属性进行设置

另外附Tomcat JDBC Connection Pool 配置信息,中文版本

根据引用\[1\]和引用\[2\]的描述,出现"java.net.SocketException: Connection reset by peer: socket write error"异常通常是由于在客户端或服务器端的读写操作中出现问题。在引用\[2\]中提到,问题可能出在文件路径错误导致文件不存在,从而导致写操作出错。因此,建议检查文件路径是否正确,并确保文件存在。 此外,根据引用\[3\]的描述,启动Java Web服务器建立了一个socket连接,并通过点击网页上传文件的按钮来保存文件并调用发送文件的方法。因此,还需要检查与socket连接相关的代码,确保连接的正确建立和关闭。 综上所述,要解决"java.net.SocketException: Connection reset by peer: socket write error"异常,需要检查以下几个方面: 1. 检查文件路径是否正确,确保文件存在。 2. 检查与socket连接相关的代码,确保连接的正确建立和关闭。 3. 如果问题仍然存在,可以考虑进一步排查其他可能导致该异常的因素,例如网络连接问题或其他代码逻辑错误。 希望以上信息对您有帮助。如果您还有其他问题,请随提问。 #### 引用[.reference_title] - *1* [Jedis高并发下操作redis报错:java.net.SocketException: Connection reset by peer: socket write error](https://blog.csdn.net/huangdi1309/article/details/121939282)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Caused by: java.net.SocketException: Connection reset by peer: socket write error](https://blog.csdn.net/youjohLee/article/details/118075816)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [java.net.SocketException: Connection reset by peer: socket write error](https://blog.csdn.net/qq_54224923/article/details/123493218)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

椰汁菠萝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值