java.util.ConcurrentModificationException
的原因:的原因:
报错位置是
是
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
at java.util.HashMap$KeyIterator.next(HashMap.java:828)
at org.hibernate.jdbc.AbstractBatcher.closeStatements(AbstractBatcher.java:314)
at org.hibernate.jdbc.ConnectionManager.cleanup(ConnectionManager.java:382)
at org.hibernate.jdbc.ConnectionManager.close(ConnectionManager.java:324)
at org.hibernate.impl.SessionImpl.close(SessionImpl.java:298)
at org.hibernate.ejb.EntityManagerImpl.close(EntityManagerImpl.java:86)
查回源码(hibernate3.2.4 sp1)
/*** Actually releases the batcher, allowing it to cleanup internally held* resources.*/public void closeStatements() {try {releasing = true;try {if (batchUpdate!=null) batchUpdate.close();}catch (SQLException sqle) {//no big deallog.warn("Could not close a JDBC prepared statement", sqle);}batchUpdate=null;batchUpdateSQL=null;Iterator iter = resultSetsToClose.iterator();while ( iter.hasNext() ) {try {logCloseResults();( (ResultSet) iter.next() ).close();}catch (SQLException e) {// no big deallog.warn("Could not close a JDBC result set", e);}catch (Throwable e) {// sybase driver (jConnect) throwing NPE here in certain caseslog.warn("Could not close a JDBC result set", e);}}resultSetsToClose.clear();iter = statementsToClose.iterator();while ( iter.hasNext() ) {try {closeQueryStatement( (PreparedStatement) iter.next() );}catch (SQLException e) {// no big deallog.warn("Could not close a JDBC statement", e);}}statementsToClose.clear();}finally {releasing = false;}}
查回源码(hibernate3.2.7 ga)
/*** Actually releases the batcher, allowing it to cleanup internally held* resources.*/public void closeStatements() {try {releasing = true;try {if ( batchUpdate != null ) {batchUpdate.close();}}catch ( SQLException sqle ) {//no big deallog.warn( "Could not close a JDBC prepared statement", sqle );}batchUpdate = null;batchUpdateSQL = null;Iterator iter = resultSetsToClose.iterator();while ( iter.hasNext() ) {try {logCloseResults();( ( ResultSet ) iter.next() ).close();}catch ( SQLException e ) {// no big deallog.warn( "Could not close a JDBC result set", e );}catch ( ConcurrentModificationException e ) {// this has been shown to happen occasionally in rare cases// when using a transaction manager + transaction-timeout// where the timeout calls back through Hibernate's// registered transaction synchronization on a separate// "reaping" thread. In cases where that reaping thread// executes through this block at the same time the main// application thread does we can get into situations where// these CMEs occur. And though it is not "allowed" per-se,// the end result without handling it specifically is infinite// looping. So here, we simply break the looplog.info( "encountered CME attempting to release batcher; assuming cause is tx-timeout scenario and ignoring" );break;}catch ( Throwable e ) {// sybase driver (jConnect) throwing NPE here in certain// cases, but we'll just handle the general "unexpected" caselog.warn( "Could not close a JDBC result set", e );}}resultSetsToClose.clear();iter = statementsToClose.iterator();while ( iter.hasNext() ) {try {closeQueryStatement( ( PreparedStatement ) iter.next() );}catch ( ConcurrentModificationException e ) {// see explanation above...log.info( "encountered CME attempting to release batcher; assuming cause is tx-timeout scenario and ignoring" );break;}catch ( SQLException e ) {// no big deallog.warn( "Could not close a JDBC statement", e );}}statementsToClose.clear();}finally {releasing = false;}}
两个版本中的closeStatements方法不同,3.2.7中加了对ConcurrentModificationException的处理,当遇到这个异常时,就break,这样就不会再循环打印这个错误了。
查了一下jboss下的hibernate3.jar,这个包使用的是3.2.4版本的,如果修改这个错误,升级一下hibernate的版本即可。
另一个问题,商用上有两台内容服务器,部署的包一样,而环境也是一样(没认真检查),两台机都有打包电子书的操作,为什么一台机会循环打印日志,而另一台则不会呢?
认真看看hibernate3.2.7中加了对ConcurrentModificationException处理的注释:
大概意思是:这只会在很小概率下发生的,当用上事务管理和事务超时时,事务超时会通过hibernate已注册事务同步的一个单独线程进行回调,这时候这个单独的线程通过这段时间再执行任务,而同时应用的主线程也在执行,这样我们就会陷入一种像日冕物质抛射的状况,尽管这个本身就是不允许的,如果我们不采取措施处理这个问题,最终结果就是一个无止境的循环。。。
这里提及到事务超时,这里想起了内容1和内容2两台服务器,一台的日志暴涨,一台却不会,后台查一下是jboss的事务超时时间不同,内容1的是好几个小时,而内容2的是5分钟,应该跟这个有关系了。
解决方法:更换hibernate的版本和修改jboss的事务超时时间。