用AOP实现业务service的重新调用(一)

阅读更多
项目配置

       struts+spring+ibatis

       Websphere+as400+db2

 

遇到的问题

       点击web页面上的一个button,调用后端的业务逻辑,再通过dao访问数据库进行各种事务操作(增删改查等等),但是同样的操作,同样的数据,有的时候偶尔会失败,通过查看日志文件,发现root原因是下面这个exception.

StaleConnectionException,原因是使用中的db connection是失效连接.而且发生异常的时间点没有任何规律.

 

Caused by: 

com.ibm.websphere.ce.cm.StaleConnectionException: [SQL0901] SQLシステム・エラー。

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:80)

at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:57)

at java.lang.reflect.Constructor.newInstance(Constructor.java:539)

at com.ibm.websphere.rsadapter.GenericDataStoreHelper.mapExceptionHelper(GenericDataStoreHelper.java:621)

at com.ibm.websphere.rsadapter.GenericDataStoreHelper.mapException(GenericDataStoreHelper.java:680)

at com.ibm.ws.rsadapter.AdapterUtil.mapException(AdapterUtil.java:2267)

at com.ibm.ws.rsadapter.jdbc.WSJdbcUtil.mapException(WSJdbcUtil.java:1191)

at com.ibm.ws.rsadapter.jdbc.WSJdbcPreparedStatement.execute(WSJdbcPreparedStatement.java:635)

at sun.reflect.GeneratedMethodAccessor111.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)

at java.lang.reflect.Method.invoke(Method.java:613)

at com.ibatis.common.jdbc.logging.PreparedStatementLogProxy.invoke(PreparedStatementLogProxy.java:62)

at com.sun.proxy.$Proxy29.execute(Unknown Source)

at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQueryProcedure(SqlExecutor.java:289)

at com.ibatis.sqlmap.engine.mapping.statement.ProcedureStatement.sqlExecuteQuery(ProcedureStatement.java:34)

at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:173)

at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForObject(GeneralStatement.java:104)

at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:561)

at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:536)

at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForObject(SqlMapSessionImpl.java:93)

at org.springframework.orm.ibatis.SqlMapClientTemplate$1.doInSqlMapClient(SqlMapClientTemplate.java:210)

at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:168)

at org.springframework.orm.ibatis.SqlMapClientTemplate.queryForObject(SqlMapClientTemplate.java:208)     

 

采取的各种对策

       网上查了各种解决方法,但是试用以后问题仍然没有解决,最后,通过阅读ibm的官方文档后,问题锁定到了ibm的数据库连接池上,ibm的数据库连接池中的连接并不能百分之百地保证是有效连接,但是一旦取得了无效连接,紧接着下一次取得的连接肯定是有效的连接.推荐的方法有两种:

       

       方案A:在每次执行业务sql之前,先调用一个test sql,来试验连接是否有效,有效的话再执行业务sql,但是很明显这样会降低效率,而且关键是试用了以后,并没有解决我们的问题,因为StaleConnectionException的触发时机很随机,test sql的时候连接是好用的,但是到执行业务sql的中途会突然无效,这样一来仍然会失败.

       

       方案B:在应用层面来解决问题,在action调用service开始事务处理的时候,如果StaleConnectionException发生,那么我们再重新调用一次service,相当于重试,因为ibm连接池能够保证获取无效连接后,紧接着获取的肯定是有效的连接.当然重试次数可以自己决定,一般重试一次就OK,次数太多的话,前端页面会明显变慢.

 

所以,我们最终选择了方案B.自己动手,在前端感知不到的情况下,后端重试一次service调用.

 

具体的落地实现请参照

用AOP实现业务service的重新调用(二)

 

你可能感兴趣的:(SQL0901,websphere,as400,db2)