你的分享就是我们的动力 ---﹥

ORA-17410错误

时间:2014-09-02 17:44来源:www.chengxuyuans.com 点击:

最近做了一个基于手机客户端webview技术的小项目,项目的架构很简答,就是Spring MVC+Hibernate,后端的数据库为Oracle 10g,项目初期功能非常简单,就是简单的单点登录功能,登录完成之后,就简单的记录一下登录日志。项目在测试环境顺利测试通过,上线到的生产环境,因为是新项目,没有对外发布,只是内部测试使用,访问量非常的小,但是就是这样的情况下,系统竟然报错了,异常如下

??

Hibernate: insert into T_USER_LOGIN_LOG (LOGIN_TYPE, BAK1, MOBILE, LOGIN_TIME, BAK3, LOGIN_COST_TIME, BAK2, serv_id, ID) values (?, 
?, ?, ?, ?, ?, ?, ?, ?)

2014-08-19 00:17:11,180 [WARN] - SQL Error: 17410, SQLState: null [org.hibernate.util.JDBCExceptionReporter.logExceptions(JDBCExcept
ionReporter.java:100)] 
21753832 [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.util.JDBCExceptionRepor
ter  - SQL Error: 17410, SQLState: null
21753832 [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.util.JDBCExceptionRepor
ter  - SQL Error: 17410, SQLState: null

2014-08-19 00:17:11,181 [ERROR] - 无法从套接字读取更多的数据 [org.hibernate.util.JDBCExceptionReporter.logExceptions(JDBCExceptionRe
porter.java:101)] 
21753833 [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] ERROR org.hibernate.util.JDBCExceptionRepo
rter  - 无法从套接字读取更多的数据
21753833 [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] ERROR org.hibernate.util.JDBCExceptionRepo
rter  - 无法从套接字读取更多的数据

2014-08-19 00:17:11,181 [WARN] - SQL Error: 17410, SQLState: null [org.hibernate.util.JDBCExceptionReporter.logExceptions(JDBCExcept
ionReporter.java:100)] 
21753833 [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.util.JDBCExceptionRepor
ter  - SQL Error: 17410, SQLState: null
21753833 [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.util.JDBCExceptionRepor
ter  - SQL Error: 17410, SQLState: null

2014-08-19 00:17:11,182 [ERROR] - 无法从套接字读取更多的数据 [org.hibernate.util.JDBCExceptionReporter.logExceptions(JDBCExceptionRe
porter.java:101)] 
21753834 [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] ERROR org.hibernate.util.JDBCExceptionRepo
rter  - 无法从套接字读取更多的数据
21753834 [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] ERROR org.hibernate.util.JDBCExceptionRepo
rter  - 无法从套接字读取更多的数据

2014-08-19 00:17:11,183 [ERROR] - Could not synchronize database state with session [org.hibernate.event.def.AbstractFlushingEventLi
stener.performExecutions(AbstractFlushingEventListener.java:324)] 
org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
        at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:14

?只是一条简单的insert语句,没有其他复杂的业务逻辑,而且这个问题在测试环境上也没有出现过,而且还是偶尔出现。

?

?

?? 从错误上看,应该是数据库连接不正常导致的,

?? 排查原因:

  • 网络问题,内网之中访问,无防火墙,不是网络原因。
  • 网上说是Oracle 版本的Bug,经分析,Oracle相关的bug不会影响到现在的Oracle版本,不是版本bug原因。
  • JDBC版本原因,可能会是该原因导致的,遂将JDBC的版本升级到和Oracle版本相符的版本,但是问题依然存在。

?

??? 在绝望是时候突然想到,生产的Oracle和测试的Oracle唯一的区别是:生产的Oracle对长期闲置的数据库连接会自动断开,而我们系统使用的数据库连接池是Apache的DBCP的BasicDataSource连接池。

?

?? 于是就在本地的Oracle中修改idle_time参数为一分钟,测试,果然出现了同样的问题,问题的根源找到,但是如何解决呢?

?

??? 现在问题是:Oracle将数据库连接断开了,但是连接池却认为该连接是可以用的,就将该连接分配给了应用程序使用,连接池和应用程序在分配和使用该连接之前没有校验数据库连接的可用性。

?

?? 查看DBCP的文档和源码,发现有这4个属性可以用:

??

  • validationQuery属性,将从连接池中获取的数据库连接返回给调用者之前,通过这个sql查询判断其有效性, 如果设置,这个查询sql必须至少有一条数据 ,可将该属性设为select 1 from dual
  • testOnBorrow属性,确定从连接池中获取的对象是否有效,如果无效从连接池移除,然后尝试下一个对象,这个属性默认为true,可以不设置
  • testOnReturn属性,放回连接池之前判断对象是否有效,这个属性默认为false,建议设为true
  • testWhileIdle属性,通过空闲对象驱逐器判断对象是否有效,如果无效从连接池移除,默认为false。

?

至此,增加这些属性之后,连接池的配置如下

	<bean 
		>
		<property name="locations">
			<list>
				<value>classpath:jdbc.properties</value>
			</list>
		</property>
	</bean>
	<bean  
		destroy-method="close">
		<property name="driverClassName">
			<value>${jdbc.driverClassName}</value>
		</property>
		<property name="url">
			<value>${jdbc.url}</value>
		</property>
		<property name="username">
			<value>${jdbc.username}</value>
		</property>
		<property name="password">
			<value>${jdbc.password}</value>
		</property>
		<property name="maxActive">
			<value>20</value>
		</property>
		<property name="maxIdle">
			<value>3</value>
		</property>
		<property name="maxWait">
			<value>-1</value>
		</property>
		<property name="defaultAutoCommit">
			<value>false</value>
		</property>
		<!-- 将从连接池中获取的数据库连接返回给调用者之前,通过这个sql查询判断其有效性 -->
		<!-- 如果设置,这个查询sql必须至少有一条数据 -->
		<property name="validationQuery">
			<value>select 1 from dual</value>
		</property>
		<!-- 确定从连接池中获取的对象是否有效,如果无效从连接池移除,然后尝试下一个对象 -->
		<property name="testOnBorrow">
			<value>true</value>
		</property>
		<!--  放回连接池之前判断对象是否有效-->
		<property name="testOnReturn">
			<value>true</value>
		</property>
		<!-- 通过空闲对象驱逐器判断对象是否有效,如果无效从连接池移除 -->
		<property name="testWhileIdle">
			<value>true</value>
		</property>
	</bean>

?

?

在生产上测试,问题得到解决。

?

?

转载注明地址:http://www.chengxuyuans.com/oracle/81347.html