No more data to read from socket 问题分析

1.问题描述

        程序在测试环境和生产环境运行都没有问题,但生产数据库的数据出了问题,排查服务器日志发现抛出以下异常信息(截选):

[2021-07-07 17:32:25][ERROR][PlatformMappingExceptionResolver.java Line:27 (doResolveException)] org.springframework.dao.RecoverableDataAccessException:
### Error querying database.  Cause: java.sql.SQLRecoverableException: No more data to read from socket
### The error may exist in file [/u01/FQM/apps/FQM/WEB-INF/classes/com/qdairlines/mapperfoc/AirportMapper.xml]
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT      AIRPORT_4CODE code4,   AIRPORT_3CODE code3,   CITY_CH_NAME cityName,   AIRPORT_CH_NAME airportName,   IS_SPECIAL  special        FROM T7001   where   ? like '%' || AIRPORT_4CODE ||'%'
### Cause: java.sql.SQLRecoverableException: No more data to read from socket
; SQL []; No more data to read from socket; nested exception is java.sql.SQLRecoverableException: No more data to read from socket
        at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:98)
        at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
        at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
        at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)
        at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:371)
        at com.sun.proxy.$Proxy14.selectList(Unknown Source)
        at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:198)
        at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:119)
        at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:63)
        at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52)
        at com.sun.proxy.$Proxy185.ListAirportView(Unknown Source)
        at com.qdairlines.service.airport.impl.AirportServiceImpl.ListAirportView(AirportServiceImpl.java:48)
        at com.qdairlines.controller.dict.Select2Controller.airportView(Select2Controller.java:189)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)

2.问题原因

        因为使用了连接池,当从连接池取得的connection失效或者超时的时候,使用这个连接来进行数据库操作就会抛出以上异常。        

3.解决方案

        让数据库连接池在给你返回connection之前,检查该connnection是否超时或者失效,如果是,则evict这个connection,并返回一个可用的connection。 

        具体配置如下:

<bean id="dataSourceSC" class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close">
        <!-- 驱动名  -->
		<property name="driverClassName" value="${jdbc.driverClassName}" />
        <!-- 数据库url  -->
		<property name="url" value="${jdbc.url}" />
        <!-- 用户名  -->
		<property name="username" value="${jdbc.username}" />
        <!-- 密码  -->
		<property name="password" value="${jdbc.password}" />
        <!-- 初试连接数  -->
		<property name="initialSize" value="10" />
        <!-- 最大活跃数  -->
		<property name="maxActive" value="30" />
        <!-- 最大空闲数  -->
		<property name="maxIdle" value="15" />
        <!-- 最小空闲数  -->
		<property name="minIdle" value="5" />
        <!-- 程序中的连接不使用后是否被连接池回收 -->
		<property name="removeAbandoned" value="true" />
        <!-- 连接在所指定的秒数内未使用才会被删除(秒)  -->
		<property name="removeAbandonedTimeout" value="60" />
        <!-- 最长等待时间  -->
		<property name="maxWait" value="10000" />
        <!-- 表示在回收连接的时候,在日志中输出回收的连接的信息,包括是在哪用的这个连接,可以用来追踪连接溢出  -->
		<property name="logAbandoned" value="true" />
        <!-- 检查该connnection是否超时或者失效 -->
        <!-- 如果为true(默认为false),当应用向连接池申请连接时,连接池会判断这条连接是否是可用的  -->
		<property name="testOnBorrow">
			<value>true</value>
		</property>
        <!-- 如果为true(默认为false),当应用向连接池申请连接时,连接池会判断这条连接是否是可用的  -->
		<property name="testOnReturn">
			<value>true</value>
		</property>
        <!-- 如果为true(默认true),当应用向连接池申请连接,并且testOnBorrow为false时,连接池将会判断连接是否处于空闲状态,如果是,则验证这条连接是否可用  -->
		<property name="testWhileIdle">
			<value>true</value>
		</property>
        <!-- 连接在池中保持空闲而不被空闲连接回收器线程,(如果有)回收的最小时间值,单位毫秒  -->
		<property name="minEvictableIdleTimeMillis">
			<value>180000</value>
		</property>
        <!-- 在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位.如果设置为非正数,则不运行空闲连接回收器线程  -->
		<property name="timeBetweenEvictionRunsMillis">
			<value>360000</value>
		</property>
        <!-- SQL查询,用来验证从连接池取出的连接,在将连接返回给调用者之前.如果指定,则查询必须是一个SQL SELECT并且必须返回至少一行记录  -->
		<property name="validationQuery">
			<value>SELECT 1 FROM SYS.DUAL</value>
		</property>
	</bean>

4.相关知识

4.1 数据库链接,常见的问题

<1> 数据库意外重启后,原先的数据库连接池能自动废弃老的无用的链接,建立新的数据库链接

<2> 网络异常中断后,原先的建立的 tcp 链接,应该能进行自动切换。比如网站演习中的交换机重启会导致网络瞬断

<3> 分布式数据库中间件,比如 cobar 会定时的将空闲链接异常关闭,客户端会出现半开的空闲链接。

4.2 常见问题解决思路

<1> sql 心跳检查 ( 主动式 )

<2> 拿链接尝试一下,发现处理失败丢弃链接,探雷的请求会失败几个  ( 牺牲小我,完成大我的精神 )

<3> 设置合理的空闲链接的超时时间,避免半开链接 ( 懒模式,解决半开链接 )

4.3 Sql 心跳检查几点思考

4.3.1 性能问题

        目前网站的应用大部分的瓶颈还是在I/O这一块,大部分的I/O还是在数据库的这一层面上,每一个请求可能会调用10来次SQL查询,如果不走事务,一个请求会重复获取链接,如果每次获取链接,比如在testOnBorrow都进行validateObject,性能开销不是很能接受,可以假定一次SQL操作消毫0.5~1ms(一般走了网络请求基本就这数)

4.3.2 成本和收益

        网站异常数据库重启,网络异常断开的频率是非常低的,一般也就在数据库升级,演习维护时才会进行,而且一般也是选在晚上,访问量相对比较低的请求,而且一般会有人员值班关注,所以异步的validateObject是可以接受,但一个前提需要确保能保证在一个合理的时间段内,数据库能完成自动重联。

5.参考资料:

c3p0官方文档:http://www.mchange.com/projects/c3p0/index.html#configuring_recovery

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
"nomoredatatoreadfromsocket" 这个词组的意思是“无法从套接字读取更多的数据”。它通常用于描述网络通信中的问题,表明一个程序或计算机无法继续从套接字接收数据,可能是因为数据已经全部接收完毕,或者出现了某些错误导致连接中断。这个错误通常出现在计算机网络编程中,表示无法从套接字读取更多的数据。这种情况可能发生在以下情况下: 1. 套接字已经关闭:这可能是因为远程主机已经关闭了连接,或者因为本地主机在读取数据之前已经关闭了套接字。 2. 数据已经被完全读取:如果你在一个循环中读取套接字中的数据,那么当读取完所有数据后,你可能会遇到这个错误。 3. 网络错误:这可能是由于网络中断或其他网络错误导致的。 要解决这个问题,你可以尝试以下几个步骤: 1. 确保套接字没有被关闭:在尝试读取套接字之前,请确保套接字已经建立连接,并且远程主机没有关闭连接。 2. 检查是否已经读取完所有数据:如果你正在读取套接字中的数据,可以检查是否已经读取完所有数据。如果没有,请继续读取,直到数据全部读取完毕。 3. 检查网络连接:如果套接字已经建立连接,并且你仍然无法读取数据,可能是由于网络中断或其他网络错误导致的。可以尝试重新连接网络或者联系网络管理员解决问题。 希望这些信息能够帮助你解决问题
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值