【原】was的一次数据库连接不了的处理记录

环境:WAS 7.0.0.0
Jdk :自带1.6
Linux环境:Linux, version 2.6.18-194.1.AXS3
Database 产品版本:Oracle Database 11g Release 11.1.0.0.0 - Production
数据源配置驱动:11.1.0.1.0  (后来更换 11.2.0.1.0 版本)

遇到的几个棘手问题:
1.

写道

引用
Error while registering Oracle JDBC Diagnosability MBean.
javax.management.MalformedObjectNameException: Invalid character '
' in value part of property
at javax.management.ObjectName.construct(ObjectName.java:613)
at javax.management.ObjectName.<init>(ObjectName.java:1405)
at oracle.jdbc.driver.OracleDriver.registerMBeans(OracleDriver.java:303)
at oracle.jdbc.driver.OracleDriver$1.run(OracleDriver.java:213)
at java.security.AccessController.doPrivileged(AccessController.java:202)
at oracle.jdbc.driver.OracleDriver.<clinit>(OracleDriver.java:209)
at java.lang.J9VMInternals.initializeImpl(Native Method)
at java.lang.J9VMInternals.initialize(J9VMInternals.java:200)
at java.lang.J9VMInternals.initialize(J9VMInternals.java:167)
at java.lang.Class.forNameImpl(Native Method)
at java.lang.Class.forName(Class.java:136)
at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1415)
at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1371)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:81)
at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:114)
at org.hibernate.cfg.Configuration.buildSettingsInternal(Configuration.java:2833)
at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2829)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1840)
at



解决:
发现还是jdbc驱动问题,原因因该是与bug有关,因此从新从otn.oracle.com下载驱动升级解决问题。
ojdbc6.jar的驱动版本可以运行java -jar ojdbc6.jar查看,如果是Oracle 11.1.0.6.0-Production+ JDBC 4.0 compiled with JDK6,带+号就是补丁版本,否则是没有打补丁的,仍然可能出错。
或者直接下载 Oracle 11.1.0.7.0-Production JDBC 4.0 compiled with JDK6 这个包的ojdbc6.jar
下载地址

引用
http://www.oracle.com/technology/tech/java/sqlj_jdbc/index.html


WAS数据源配置:
我的项目中,涉及到多个库的连接,并且在程序中,对多个库有操作。其中每个库本身又保持自己业务库的连接。项目中自己的库,一方面通过注入,由hibernate去管理。作为自己的本身业务库,另一方面又注入到一个连接工厂,维持一个所有数据源的Map。供程序调用。而所有的连接是用was的连接池管理。
刚开始数据总是会报一个com.ibm.websphere.ce.cm.StaleConnectionException的异常。
  原因分析:WebSphere并不保证缓存的连接都是有效的,在这种情况下当用户从连接池中取得了一个失效的连接并且用来进行数据库操作时,WebSphere就会抛出StaleConnectionException。在StaleConnectionException出现之前,用户无法判断这是否为一个无效连接。详见:

引用
http://www.ibm.com/developerworks/cn/websphere/library/techarticles/0601_chenzhh/index.html

文章中说到,是由于websphere与数据库之间的连接中断导致。这可以验证我之前遇到的情况。日志里面有数据库的IO异常错误。网络不稳定可能是一个因素。但是后来,我调整了环境后,仍然有错。这里的连接池的缓存可能还跟连接池的配置项有关。因为我自己的程序对数据库的操作数据比较多,在程序开始前,先从一个库到查询大量的数据,再到另一个库里去插入大量的数据。而我获取连接在一开始就获取了,由于长时间的连接闲置,was连接池可能会把物理连接给断掉。这可能也是导致无效连接的一个因素。后来我把获取连接的位置调整了一下,问题有了好转。上述链接,说到避免无效连接,其实就是在连接之前加个测试语句。这在proxool等连接池组件都有配置实现,但是我们用jndi在程序里,就可以通过捕获异常,再去获取连接。这里给出我自己的代码:

Java代码 

do {    
   Statement stmt = null;    
   try {    
     if (retryCount == 0) {    
        conn = getDataSource(alias).getConnection();    
      } else {    
                Properties jndiMap = new Properties();    
                    jndiMap.put(“1”,”jndi/1”);    
                    jndiMap.put(“2”,”jndi/2”);    
                    jndiMap.put(“3”,”jndi/3”);    
		Properties env = new Properties();    
		env.put(Context.INITIAL_CONTEXT_FACTORY,    
		"com.ibm.websphere.naming.WsnInitialContextFactory");    
		Context context = new InitialContext(env);    
		DataSource ds = (DataSource) context.lookup(jndiMap    
		.getProperty(alias));    
		conn = ds.getConnection();    
	}    
	stmt = conn.createStatement();    
	stmt.execute("select 1 from dual");    
} catch (StaleConnectionException sce) {    
	if (retryCount < 3) {    
    		retry = true;    
		retryCount++;    
	} else {    
	retry = false;    
        }    
} catch (Exception e) {    
   	e.printStackTrace();    
} finally {    
	try {    
 	    if (stmt != null) {    
	       stmt.close();    
	    }    
	    if (conn != null && retry) {    
	       conn.close();    
	    }    
	} catch (Exception e) {    
	    e.printStackTrace();    
	}    
    }    
} while (retry);   

注:(1) 不同版本的jndi的提取方式可能不一样。
  (2) 该异常所在websphere的jar包:以当前环境为例,在 plugins/com.ibm.ws.runtime.jar(自己确实找了很久,才引入进来编译的代码)
  当我就要觉得大功告成了,发现又现一个很严重的问题。系统启动没有几分钟,就有异常抛出:数据采集:数据入库异常java.lang.NullPointerException。数据长时间重连后,依旧获取不到连接,就导致了抛异常了,到systemOut.log 上一看,发现问题:

写道

引用
[13-1-29 19:46:39:163 GMT+08:00] 0000002d FreePool E J2CA0045E: 对资源 jndi/sjjh 调用方法 createOrWaitForConnection 时,没有可用的连接。
[13-1-29 19:46:39:165 GMT+08:00] 00000016 FfdcProvider I com.ibm.ws.ffdc.impl.FfdcProvider logIncident FFDC1003I: 已在 /opt/IBM/WebSphere/AppServer/profiles/AppSrv01/logs/ffdc/server1_55a955a9_13.01.29_19.46.39.1622748.txt com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection 299 发出 FFDC 事件。


额外的提示:
First failure data capture(FFDC) 工具是 WebSphere 小组开发的一款可以在第一次异常发生时对其进行详细数据捕获的工具。我们将其移植进入 IBM Systems Director ,并对其功能进行了进一步的封装,从而使其能够针对 Director 这款软件中的各种异常数据进行捕获。FFDC 机制在 Director 启动时随之启动,然后监听异常数据,直至 Director 被关闭。
  
通过查看FFDC事件日志,报出以下日志:

写道

引用
[13-1-29 19:25:41:587 GMT+08:00] FFDC Exception:com.ibm.websphere.ce.j2c.ConnectionWaitTimeoutException SourceId:Max connections reached ProbeId:869 Reporter:com.ibm.ejs.j2c.PoolManager@28cc28cc
com.ibm.websphere.ce.j2c.ConnectionWaitTimeoutException: Connection not available, Timed out waiting for 180030
at com.ibm.ejs.j2c.FreePool.createOrWaitForConnection(FreePool.java:1562)
at com.ibm.ejs.j2c.PoolManager.reserve(PoolManager.java:2436)
at com.ibm.ejs.j2c.ConnectionManager.allocateMCWrapper(ConnectionManager.java:955)
at com.ibm.ejs.j2c.ConnectionManager.allocateConnection(ConnectionManager.java:609)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:646)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:613)
……(中间省略)……
==> Performing default dump from com.ibm.ejs.j2c.DiagnosticModuleForJ2C :Tue Jan 29 19:25:41 GMT+08:00 2013
Maximum number of connections has been reached, and the connection request has been waiting longer than:ConnectionWaitTime. Two possible solutions : increase the max number of connections, or increase the:ConnectionWaitTime.:
Maximum Connections = :10
Current number of connections = :10
Connection Wait Timout = :180

日志给出了很详细的处理方法,增大最大连接数,或者增大连接等待的时间,因为180秒的等待时间,当连接达到最大的连接数,获取连接时间超过180秒,就会抛出异常了。如果资源允许的话,我们很喜欢调整一下,连接数调整到100,连接等待时间再调整一下。可是情况依然没有好转,100个连接数,启动没有10分钟,就耗尽了。问题没有这么简单。
由于是现场的问题,立马让现场,抓了一个数据库的情况:

写道

引用
Select userName,count(userName) from v&session group by userName

100的连接耗尽,数据库的保有连接是 26 。
  到这,我有点疑惑了,难不成是was连接池的连接池与数据库的连接没有同步。也就是网上有那么几个稀少的提问:was7.0版本的连接池不会自动释放连接,有没有人碰到,我这里的情况貌似是这样,想想这是不是ibm本身的bug问题。开始查找IBM fix List。发现有关J2CA0045E 问题报错, 有两处提到:
  

引用
http://www-01.ibm.com/support/docview.wss?uid=swg21323294

写道

引用
J2CA0045E: Connection not available while invoking method
createOrWaitForConnection for resource jdbc/BPEDB.CWWBB0638E: Failed to connect to the database. The error reported by thedatabase is: com.ibm.websphere.ce.cm.ConnectionWaitTimeoutException:Connection not available, Timed out waiting for 180000.
Cause
This problem likely has two of the following causes:
The connection pool is incorrectly configured
The database settings for the maximum number of connections is incorrect or is lower than the settings of the connection pool in WebSphere Application Server
The embedded Derby database is used for processing the high-workload scenario, or the network deployment Derby server is improperly configured


原因描述的都很简单。连接池配置问题,最小超出最大连接,也属于配置问题,第三个跟我们的项目没有关系。到这里,我们不得不去考虑程序的问题了,我们又做了验证,发现这次
现场问题出来后,数据库的连接就是100了。跟之前的对比,原因:就是之前的抓数据库的信息晚了,导致was自己释放一部分的连接,所以库的保有连接是26。这个时候异常已经抛出来了。看来还应该是程序本身的问题。
后来经过查看代码发现:我们把获取连接写在了循环的里面了,而把关闭连接写在循环的外面。每次在里面通过连接工厂获取连接,当循环的次数为0或较少的时,程序在数据库上的开销几乎没有,即使有部分的连接没有关闭,由was的连接池也关闭了,不至于影响性能,但是当业务量大的时候,获取连接多,而且操作频繁,was关闭掉的连接诊断远远达不到获取连接的速度,就会抛异常了。但是这里比较奇怪的一点,当没有获取连接的时候,在程序的后端,执行close操作,竟然没有报空指针异常,虽然捕获了异常,也没有任何输出,该代码端的结束的log输出也不见了。这让我有点奇怪,这也是我在这个问题上查找原因花了不少时间的一个方面。

总结:was在连接池上的异常,多半都是自己程序上没有及时关闭导致的。在你疯狂的为bug着急的时候,请先看看自己的代码。毕竟第三方的bug是少之又少的。

猜你喜欢

转载自rmzdb.iteye.com/blog/1781187