[b]运行环境:[/b]
Aix + WebSphere 6.1 + Oracle + Quartz1.65 + Sping2.5.6 +Hibernate 3.3.1
[b]现象:[/b]
WebSphere 的Node & Server挂死,JVM堆栈溢出,WebSphere 所在分区被JVM core dump 文件塞满
[b]原因:[/b]
Quartz 管理的线程运行在非容器托管状态(不受WebSphere控制),获取不到J2EE context,并且线程中使用到了Hibernete,在试图通过java:comp/UserTransaction查询JTA时throw NamingException,而Hibernete JTATransactionFactory.java 如下代码存在BUG:
protected UserTransaction getUserTransaction() { log.trace( "Attempting to locate UserTransaction via JNDI [{}]", getUserTransactionName() ); try { UserTransaction ut = ( UserTransaction ) getInitialContext().lookup( getUserTransactionName() ); if ( ut == null ) { throw new TransactionException( "Naming service lookup for UserTransaction returned null [" + getUserTransactionName() +"]" ); } log.trace( "Obtained UserTransaction" ); return ut; } catch ( NamingException ne ) { throw new TransactionException( "Could not find UserTransaction in JNDI [" + getUserTransaction() + "]", ne ); } }
,其中[color=red]throw new TransactionException( "Could not find UserTransaction in JNDI [" + getUserTransaction() + "]"[/color] ,按作者的意思应该是getUserTransactionName() 误写成了getUserTransaction() 导致无限递归调用
[b]解决办法 :[/b]
[b]方案1:[/b]
重写JTATransactionFactory.java 的getUserTransaction() 方法
代码如下
protected UserTransaction getUserTransaction() { log.trace( "Attempting to locate UserTransaction via JNDI [{}]", getUserTransactionName() ); if(uTran != null) return uTran; try { uTran = ( UserTransaction ) getInitialContext().lookup( getUserTransactionName() ); if ( uTran == null ) { uTran = ( UserTransaction ) getInitialContext().lookup( CLIENT_USER_TRANSACTION_NAME ); if(uTran != null) return uTran; else throw new TransactionException( "Naming service lookup for UserTransaction returned null [" + getUserTransactionName() +"]" ); } log.trace( "Obtained UserTransaction" ); return uTran; } catch ( NamingException ne ) { try { uTran = ( UserTransaction ) getInitialContext().lookup( CLIENT_USER_TRANSACTION_NAME ); } catch (NamingException e) { e.printStackTrace(); } if(uTran != null) return uTran; else throw new TransactionException( "Could not find UserTransaction in JNDI [" + getUserTransactionName() + "]", ne ); } }
其中CLIENT_USER_TRANSACTION_NAME= [color=blue]"jta/usertransaction"[/color]
[b]方案2:[/b]
自定义hibernate.transaction.factory_class类
使用Spring注入usertransaction
重载getUserTransaction
protected UserTransaction getUserTransaction() { return userTransaction; }