求助!Spring下使用JNDI数据源时JDBCTemplate数据库连接关闭的问题!

天上的云像白菜 2016-03-04 04:23:14
最近在接手一个项目的时候,偶尔出现一个问题,JDBCTemplate用得好好的,突然后台狂报错,其中一个报错内容如下:
org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [select CNTR_EF_ID from ship_bill where bill_no = ?]; SQL state [null]; error code [17008]; 关闭的连接; nested exception is java.sql.SQLException: 关闭的连接
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:602)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:636)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:665)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:673)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:728)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:744)
at net.huadong.eservices.edi.action.DeliorAction.generateDeliorIFV(DeliorAction.java:180)
at sun.reflect.GeneratedMethodAccessor685.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.webbuilder.utils.SysUtil.executeMethod(SysUtil.java:55)
at com.webbuilder.controls.Method.descript(Method.java:11)
at com.webbuilder.controls.Control.create(Control.java:50)
at com.webbuilder.common.Parser.createControl(Parser.java:546)
at com.webbuilder.common.Parser.parseElements(Parser.java:462)
at com.webbuilder.common.Parser.parseElements(Parser.java:465)
at com.webbuilder.common.Parser.parse(Parser.java:165)
at com.webbuilder.common.Main.doGet(Main.java:193)
at com.webbuilder.common.Main.doPost(Main.java:266)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:643)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.resteasy.plugins.server.servlet.FilterDispatcher.doFilter(FilterDispatcher.java:63)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at net.huadong.port.lsmp.filter.LoginFilter.doFilter(LoginFilter.java:101)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:206)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:179)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at net.huadong.pass.core.platform.webService.WebServiceFilter.doFilter(WebServiceFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11NioProcessor.process(Http11NioProcessor.java:891)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:750)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:2282)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)

JNDI配置如下:
<Resource name="jdbc/shjjhy" 
auth="Container" type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@***"
username="***"
password="***"
testOnBorrow="true"
testWhileIdle="true"
testOnReturn="true"
validationQuery="select 1 from dual"
minEvictableIdleTimeMillis="10000"
timeBetweenEvictionRunsMillis="10000"
maxActive="500"
maxIdle="50"
maxWait="1000" removeAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true" initialSize="5" />


Spring的配置如下:
<bean id="dataSourceJNDI" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/shjjhy</value>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
abstract="false" lazy-init="false">
<property name="dataSource">
<ref bean="dataSourceJNDI" />
</property>
</bean>

JDBCTemplate默认是使用的单例模式,在系统中我们是这样获取JDBCTemplate的:

WebApplicationContext ctx = (WebApplicationContext) request
.getAttribute("WebApplicationContext");
JdbcTemplate jt = (JdbcTemplate) ctx.getBean("jdbcTemplate");


基本上是所有只要使用JDBCTemplate进行数据操作的地方都会报错,我在后台监控也看到了,数据连接池最高的时候也就20个连接,而且关键就是在系统运行一段时间后才会出这个问题,时间不确定,有时候一两个星期出现,有时候一天出现两三次,每次都只能通过重启Tomcat来解决。

我想了好久,觉得最大的可能性是,JDBCTemplate在某个地方被强制关闭了,但是JDBCTemplate的Connection关闭我记得是自己处理的啊,所以我也不知道到哪里去找错误的根源,所以来请教各路大神!!!看各位是否遇到过这种情况;

我总结下:
1、一般都是系统在运行一段时间后才会报错,而且只要是使用JDBCTemplate的地方就会报错,如果是直接获取Connection来调用是不会报错的;
2、连接数最高不超过20,远远没有达到连接池的限制,如图:

3、每次都只能通过重启服务器解决此问题,是否有好的解决方案或者思路?
...全文
1016 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
后来我这里找了很久的错误,发现是因为有时候会有后台数据库死锁的情况,在数据库中KILL掉连接后,就会出现这样的问题; 这个连接池解决不了这个问题,只能优化系统代码,减少数据库死锁情况的出现。感谢这么多大神的关心与回复!
baidu_22481969 2016-10-11
  • 打赏
  • 举报
回复
引用 19 楼 yzjdt 的回复:
[quote=引用 18 楼 baidu_22481969 的回复:] 楼主你这个监控的工具是什么?谢谢告知
javaMelody 要不要帮忙我看看这个问题啊,现在还没有解决。就是在数据库中KILL掉SESSION后,连接已经关闭了,但是tomcat认为还是有效的,继续放入连接池中了。。[/quote] 我也是遇到相似的问题了,不过我已经排除不是代码的问题了,你看看楼上的几位,要不就是连接池的配置问题。我也还在解决中。。
  • 打赏
  • 举报
回复
引用 18 楼 baidu_22481969 的回复:
楼主你这个监控的工具是什么?谢谢告知
javaMelody 要不要帮忙我看看这个问题啊,现在还没有解决。就是在数据库中KILL掉SESSION后,连接已经关闭了,但是tomcat认为还是有效的,继续放入连接池中了。。
baidu_22481969 2016-10-09
  • 打赏
  • 举报
回复
楼主你这个监控的工具是什么?谢谢告知
  • 打赏
  • 举报
回复
求助各位!!@ 楼上所有人! 经过几个月的查找问题,终于发现了原因所在,这个连接会丢失,是因为有人在Oracle数据库把Lock的Session给KILL掉了,只要有一个Session被KILL(即使是INACTIVE的Session),tomcat连接池就会报关闭的连接的错误! 所以求问各位大神,tomcat下的JNDI数据库连接池如何配置数据库连接重连的功能?
xiaohuashenshou 2016-03-07
  • 打赏
  • 举报
回复
没办法回答你那么详细来了,呵呵,这个东西N多年不用了,里面到底怎么运行的我也记不清楚了,有空你看下源码吧,或许能找到解决办法
skran 2016-03-07
  • 打赏
  • 举报
回复
你可以先把手动获取连接的代码先屏蔽,然后观察一段时间看看。
  • 打赏
  • 举报
回复
引用 12 楼 xiaohuashenshou 的回复:
JdbcTemplate是spring封装的快速操作数据库的一套API,你可以点击进去看下源代码(这里就不提供了,没找到例子,这个东西已经被我们摒弃很多年了),肯定是不需要自己关闭的,而且后面看了下,WebApplicationContext ctx = (WebApplicationContext) request.getAttribute("WebApplicationContext"); JdbcTemplate jt = (JdbcTemplate) ctx.getBean("jdbcTemplate"); Connection con = null; try{ con = jt.getDataSource().getConnection(); con.setAutoCommit(false); /** * 业务操作 */ con.setAutoCommit(true); }catch(Exception e){ e.printStackTrace(); try { con.setAutoCommit(true); } catch (SQLException e1) { e1.printStackTrace(); } }finally{ DbUtil.closeConnection(con, true); } 这块好像是要对事物做控制,不知道有AOP这个东西么,这块是线程安全的不,你的问题很可能是线程不安全导致
当时做这个项目的时候,并没有完全按照Spring的方式来做,就算JDBCTemplate老一点也没什么大问题,但问题就是,他们很多都是把JdbcTemplate转为原始的Connection后再操作,导致这个项目里面最少用了三种JDBC的操作,AOP更加没用上。 然后您说的关于线程的,这个方法并没有加任何synchronized的关键字来控制线程安全,然后我看了一下这段代码,然后也是我的疑惑所在,JdbcTemplate虽然是单例模式,但是不应该是每次我从Spring容器里面取一个JdbcTemplate出来的时候,应该就会向连接池要一个新连接对吧?如果是这样,就算这段代码里面我手动关闭了,应该也不会造成其他地方只要一调用JdbcTemplate就会报错吧?这样的话岂不是JDBCTemplate里面永远只有一个有效的连接?所有地方调用JdbcTemplate都是使用同一个Connection来操作的?
  • 打赏
  • 举报
回复
引用 11 楼 Q80470101 的回复:
[quote=引用 10 楼 yzjdt 的回复:] [quote=引用 7 楼 Q80470101 的回复:] 一个可能的原因是,某个地方的连接没有关闭,导致连接被消耗光了。
一开始我也以为是这个原因,但是我的连接池设置了500的连接,这是很久以前以为是连接数的问题,所以设了这么大,但是我上面也给出了我们监控系统的图表,今天的最大连接数才19,但是今天就出现两次这样的问题, 我只能重启服务器才能解决。[/quote] 我建议你去检查下所有jdbc的代码(你们代码中所有的jdbc,不只是JDBCTemplate),你的现象和这个猜测很吻合。 ps: ctrl+shift+g 快捷键可以查看到所有引用。[/quote] 也就是说如果jdbc的Connection是从JdbcTemplate里面取出来的话,再关闭是很有可能出现这种问题的?
xiaohuashenshou 2016-03-07
  • 打赏
  • 举报
回复
JdbcTemplate是spring封装的快速操作数据库的一套API,你可以点击进去看下源代码(这里就不提供了,没找到例子,这个东西已经被我们摒弃很多年了),肯定是不需要自己关闭的,而且后面看了下,WebApplicationContext ctx = (WebApplicationContext) request.getAttribute("WebApplicationContext"); JdbcTemplate jt = (JdbcTemplate) ctx.getBean("jdbcTemplate"); Connection con = null; try{ con = jt.getDataSource().getConnection(); con.setAutoCommit(false); /** * 业务操作 */ con.setAutoCommit(true); }catch(Exception e){ e.printStackTrace(); try { con.setAutoCommit(true); } catch (SQLException e1) { e1.printStackTrace(); } }finally{ DbUtil.closeConnection(con, true); } 这块好像是要对事物做控制,不知道有AOP这个东西么,这块是线程安全的不,你的问题很可能是线程不安全导致
家里敷泥呀 2016-03-06
  • 打赏
  • 举报
回复
引用 10 楼 yzjdt 的回复:
[quote=引用 7 楼 Q80470101 的回复:] 一个可能的原因是,某个地方的连接没有关闭,导致连接被消耗光了。
一开始我也以为是这个原因,但是我的连接池设置了500的连接,这是很久以前以为是连接数的问题,所以设了这么大,但是我上面也给出了我们监控系统的图表,今天的最大连接数才19,但是今天就出现两次这样的问题, 我只能重启服务器才能解决。[/quote] 我建议你去检查下所有jdbc的代码(你们代码中所有的jdbc,不只是JDBCTemplate),你的现象和这个猜测很吻合。 ps: ctrl+shift+g 快捷键可以查看到所有引用。
  • 打赏
  • 举报
回复
引用 6 楼 okafor2011 的回复:
不需要显示关闭连接的
我也查了很多资料是不应该显示的关闭连接;所以我也不确定下面这段代码是不是有问题,也不轻视是否会造成我前面说的那种情况出现:

		WebApplicationContext ctx = (WebApplicationContext) request.getAttribute("WebApplicationContext");
		JdbcTemplate jt = (JdbcTemplate) ctx.getBean("jdbcTemplate");
		Connection con = null;
		try{
			con  = jt.getDataSource().getConnection();
			con.setAutoCommit(false);
			/**
			 * 业务操作
			 */
			con.setAutoCommit(true);
		}catch(Exception e){
			e.printStackTrace();
			try {
				con.setAutoCommit(true);
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		}finally{
			DbUtil.closeConnection(con, true);
		}
  • 打赏
  • 举报
回复
引用 7 楼 Q80470101 的回复:
一个可能的原因是,某个地方的连接没有关闭,导致连接被消耗光了。
一开始我也以为是这个原因,但是我的连接池设置了500的连接,这是很久以前以为是连接数的问题,所以设了这么大,但是我上面也给出了我们监控系统的图表,今天的最大连接数才19,但是今天就出现两次这样的问题, 我只能重启服务器才能解决。
  • 打赏
  • 举报
回复
引用 5 楼 luntanrenhaoduo 的回复:
你找下 select CNTR_EF_ID from ship_bill where bill_no = ? 这个sql用的会话对象是怎么操作的,不行把这段代码删掉,测试下,会不会报错还.
他这个不仅是这一个地方报错,是有很多地方都报错,我只是把其中一个错误贴出来而已,而且都是一些不相关的业务或者代码都只要用到了JDBCTemplate就会报错; 其中我拿出来的这个报错的地方是这样使用的:

String emptyBillSql = "select CNTR_EF_ID from ship_bill where bill_no = ?";
try {
	WebApplicationContext ctx = (WebApplicationContext) request
		.getAttribute("WebApplicationContext");
	JdbcTemplate jt = (JdbcTemplate) ctx.getBean("jdbcTemplate");
	for (String bill : bills) {
		if (!StringUtil.isEmpty(bill)) {
			bi = bill.split("-");
			String billEFId = "F";
			try {
				billEFId = jt.queryForObject(emptyBillSql, new Object[]{bi[0]}, String.class);
			} catch (Exception e) {
				e.printStackTrace();
				billEFId = "F";
			}
			// 以下代码省略
有的地方使用的是jt.queryForList 也一样的报错;就是那种突然就出现了,然后后台疯狂报错,全都是关闭的连接这样的错误。所以我也是怀疑是不是因为单例模式的影响,在某个地方把JDBCTemplate的连接关闭了,其他地方只要引用JDBCTemplate就都报错了。 但是我也不知道是什么样的代码能做到把JDBCTemplate的连接关闭而且让Spring不会新获取连接。
家里敷泥呀 2016-03-04
  • 打赏
  • 举报
回复
一个可能的原因是,某个地方的连接没有关闭,导致连接被消耗光了。
okafor2011 2016-03-04
  • 打赏
  • 举报
回复
不需要显示关闭连接的
江湖啊江湖 2016-03-04
  • 打赏
  • 举报
回复
你找下 select CNTR_EF_ID from ship_bill where bill_no = ? 这个sql用的会话对象是怎么操作的,不行把这段代码删掉,测试下,会不会报错还.
  • 打赏
  • 举报
回复
引用 3 楼 luntanrenhaoduo 的回复:
因为你是接手的项目,而不是你自己写的。 有些人在操作SQL时喜欢在程序里自己弄一个Connection进行操作. 而这个Connection是通过JDBCTemplate get到的,又进行了违规的操作. 至于为啥这么写...我觉得你应该去问问给你项目的那个人.
大神,我在我的项目中搜索到了一段代码,麻烦您看下,是不是这样的就会出现这样的问题?

		WebApplicationContext ctx = (WebApplicationContext) request.getAttribute("WebApplicationContext");
		JdbcTemplate jt = (JdbcTemplate) ctx.getBean("jdbcTemplate");
		Connection con = null;
		try{
			con  = jt.getDataSource().getConnection();
			con.setAutoCommit(false);
			/**
			 * 业务操作
			 */
			con.setAutoCommit(true);
		}catch(Exception e){
			e.printStackTrace();
			try {
				con.setAutoCommit(true);
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		}finally{
			DbUtil.closeConnection(con, true);
		}
然后上面的DbUtil.closeConnection(con, true);的方法如下:

public static boolean closeConnection(Connection connection,
			boolean isExcept) {
		/* 331 */boolean status = true;
		try {
			/* 333 */if ((connection != null) && (!connection.isClosed())) {
				/* 334 */if (!connection.getAutoCommit())
					try {
						/* 336 */if (isExcept)
							/* 337 */connection.rollback();
						else
							/* 339 */connection.commit();
					} catch (Exception e) {
						/* 341 */status = false;
						/* 342 */if (!isExcept)
							/* 343 */connection.rollback();
					} finally {
						/* 345 */connection.setAutoCommit(true);
					}
				/* 347 */connection.close();
				/* 348 */connection = null;
			}
		} catch (Exception e) {
			/* 351 */status = false;
		}
		/* 353 */return status;
	}
再次感谢大神的指导!
江湖啊江湖 2016-03-04
  • 打赏
  • 举报
回复
因为你是接手的项目,而不是你自己写的。 有些人在操作SQL时喜欢在程序里自己弄一个Connection进行操作. 而这个Connection是通过JDBCTemplate get到的,又进行了违规的操作. 至于为啥这么写...我觉得你应该去问问给你项目的那个人.
  • 打赏
  • 举报
回复
引用 1 楼 luntanrenhaoduo 的回复:
这种现象一般是使用了关闭的Connection, 你仔细检查下代码是不是哪个地方使用了关闭的Connection操作了?
感谢您的回复,就是这一点我很疑惑,JDBCTemplate中是自己封装了关闭数据库的连接,如何能让程序员显性的把JDBCTemplate中使用的Connection关闭呢?
加载更多回复(1)

81,091

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧