2013-05-10 14 views
5

sto usando Spring 3 con APP e sto vedendo un problema intermittente nella mia applicazione web. Ho wrapper per EntityManager JPA che chiama i metodi grezzi di EntityManager sottostanti. A volte vedo NPE quando chiamo entityManager.persist(object); Sembra che la connessione al database sia andata persa, ma non sono al 100% quale sia la causa. Qualcuno ha qualche dettaglio su cosa può aver causato l'eccezione qui sotto?Spring 3 NPE con LazyConnectionDataSourceProxy autoCommit

Primavera Versione: 3.0.6.RELEASE

Primavera linea 3 LazyConnectionDataSourceProxy.java 416:

if (this.autoCommit != null && this.autoCommit != this.target.getAutoCommit()) { 
    this.target.setAutoCommit(this.autoCommit); 
} 

Eccezione:

Caused by: java.lang.NullPointerException 
     at org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy$LazyConnectionInvocationHandler.getTargetConnection(LazyConnectionDataSourceProxy.java:416) 
     at org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy$LazyConnectionInvocationHandler.invoke(LazyConnectionDataSourceProxy.java:376) 
     at $Proxy64.prepareStatement(Unknown Source) 
     at org.hibernate.jdbc.AbstractBatcher.getPreparedStatement(AbstractBatcher.java:534) 
     at org.hibernate.jdbc.AbstractBatcher.prepareSelectStatement(AbstractBatcher.java:145) 
     at org.hibernate.id.SequenceGenerator.generate(SequenceGenerator.java:96) 
     at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:122) 
     at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49) 
     at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154) 
     at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110) 
     at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61) 
     at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:646) 
     at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:620) 
     at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:624) 
     at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:220) 
     at sun.reflect.GeneratedMethodAccessor101.invoke(Unknown Source) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:592) 
     at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240) 
     at $Proxy79.persist(Unknown Source) 
     at myapp.api.dao.impl.GenericDAOImpl.save(GenericDAOImpl.java:50) 
     at sun.reflect.GeneratedMethodAccessor100.invoke(Unknown Source) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:592) 
     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
     at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) 
     at $Proxy119.save(Unknown Source) 
     at myapp.api.service.impl.backoffice.StoringServiceImpl.store(StoringServiceImpl.java:89) 
     at myapp.api.service.impl.backoffice.StoringServiceImpl.storeIncludedFeatureMessage(StoringServiceImpl.java:68) 
     at sun.reflect.GeneratedMethodAccessor124.invoke(Unknown Source) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:592) 
     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) 
     at $Proxy168.storeIncludedFeatureMessage(Unknown Source) 
     at myapp.api.listener.backoffice.StorableMessageListener.processNew(StorableMessageListener.java:136) 
     at myapp.api.listener.backoffice.StorableMessageListener.onMessage(StorableMessageListener.java:187) 
     ... 34 more 

configurazione Primavera:

<?xml version="1.0" encoding="UTF-8"?> 
    <beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:util="http://www.springframework.org/schema/util" 
     xmlns:context="http://www.springframework.org/schema/context" 
     xmlns:aop="http://www.springframework.org/schema/aop" 
     xmlns:tx="http://www.springframework.org/schema/tx" 
     xmlns:hz="http://www.hazelcast.com/schema/spring" 
     xsi:schemaLocation=" 
     http://www.hazelcast.com/schema/spring 
     http://www.hazelcast.com/schema/spring/hazelcast-spring-2.5.xsd 
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
     http://www.springframework.org/schema/util 
     http://www.springframework.org/schema/util/spring-util-3.0.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd 
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
     http://www.springframework.org/schema/aop 
     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> 

     <!-- Generic --> 
     <context:annotation-config /> 
     <context:component-scan base-package="myapp.api" /> 
     <aop:aspectj-autoproxy/> 

     <!-- JPA --> 
     <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> 

     <tx:annotation-driven /> 

     <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" /> 

     <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
      <property name="dataSource" ref="dataSource" /> 
      <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> 
      <property name="persistenceUnitName" value="MyApp" /> 
      <property name="jpaProperties"> 
       <props> 
        <prop key="hibernate.use_sql_comments">true</prop> 
        <prop key="hibernate.generate_statistics">true</prop> 
        <prop key="hibernate.archive.autodetection">class</prop> 
        <prop key="hibernate.cache.use_second_level_cache">true</prop> 
        <prop key="hibernate.cache.provider_class">com.hazelcast.hibernate.provider.HazelcastCacheProvider</prop> 
        <prop key="hibernate.cache.use_query_cache">true</prop> 
        <prop key="hibernate.cache.use_minimal_puts">true</prop> 
       </props> 
      </property> 
     </bean> 


     <hz:hazelcast id="instance"> 
      <hz:config> 
       //rest of Hazelast config here 
      </hz:config> 
     </hz:hazelcast> 

     <hz:hibernate-region-factory id="regionFactory" instance-ref="instance"/> 

     <!-- Define JPA Provider Adapter --> 
     <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
      <property name="showSql" value="true" /> 
      <property name="generateDdl" value="true" /> 
      <property name="databasePlatform" value="org.hibernate.dialect.OracleDialect" /> 
     </bean> 

     <bean id="dataSourceTarget" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close"> 
      <property name="URL" value="jdbc:oracle:thin:@server:1525:name" /> 
      <property name="user" value="test" /> 
      <property name="password" value="123" /> 
      <property name="connectionCachingEnabled" value="true" /> 
      <property name="connectionCacheProperties"> 
       <props merge="default"> 
        <prop key="MinLimit">5</prop> 
        <prop key="MaxLimit">50</prop> 
       </props> 
      </property> 
     </bean> 

     <bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy"> 
      <property name="targetDataSource" ref="dataSourceTarget"/> 
     </bean> 


     <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
      <property name="entityManagerFactory" ref="entityManagerFactory"/> 
      <property name="dataSource" ref="dataSource"/> 
     </bean> 

     <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/> 

     <bean id="genericDAO" class="myapp.api.dao.impl.GenericDAOImpl"> 
      <constructor-arg> 
       <value>java.io.Serializable</value> 
      </constructor-arg> 
     </bean> 

     <bean id="springContextHolder" class="myapp.api.util.SpringContextHolder" factory-method="getInstance" /> 

<bean id="executionInterceptor" class="myapp.api.listener.backoffice.ExecutionInterceptor" /> 

     </beans> 

AOP Error Handler:

package myapp.api.listener.backoffice; 


import javax.jms.Message; 

import org.aspectj.lang.JoinPoint; 
import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.AfterReturning; 
import org.aspectj.lang.annotation.AfterThrowing; 
import org.aspectj.lang.annotation.Around; 
import org.aspectj.lang.annotation.Aspect; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Qualifier; 
import org.springframework.jms.core.JmsTemplate; 
import org.springframework.util.StopWatch; 

@Aspect 
public class ExecutionInterceptor extends BaseListener{ 
    //protected Log log = LogFactory.getLog(this.getClass()); 
    private String errorDestination="ErrorQ"; 
    @Autowired 
    @Qualifier("jmsTemplate") 
    JmsTemplate jmsTemplate; 

    @Around("execution(* onMessage(javax.jms.Message))") 
    public Object aroundOnMessage(ProceedingJoinPoint pjp) throws Throwable{ 
     StopWatch stopWatch = new StopWatch(); 
     stopWatch.start(); 
     Object retVal = pjp.proceed(); 
     stopWatch.stop(); 
     log.trace(pjp.getSignature().getName() + " Execution Time: " + stopWatch.getTotalTimeMillis()+" ms"); 
     return retVal; 
    } 
    @AfterReturning("execution(* onMessage(javax.jms.Message))") 
    public void afterOnMessage(){ 
     // logic to capture time 
     log.debug("*****************************EXIT ONMESSAGE*******************************"); 

    } 

    @Around("execution(* commit(..))") 
    public Object aroundCommit(ProceedingJoinPoint pjp) throws Throwable{ 
     try{ 
      return pjp.proceed(); 
     }catch(Throwable ex){ 
      log.error("Unexpected Error occured during database commit routing message to ErrorQ", ex); 
      jmsTemplate.convertAndSend(errorDestination, ex); 
      throw ex; 
     }finally{ 
      log.trace("Commiting Transaction..."); 
     } 

    } 
    @AfterThrowing(value="execution(* onMessage(javax.jms.Message) throws java.lang.RuntimeException)",throwing="ex") 
    public void afterThrowingOnMessage(JoinPoint jp,RuntimeException ex) throws RuntimeException{ 
     log.trace("Unexpected Error occured during onMessage processing routing to ErrorQ"); 
     log.error("{{ERROR}}", ex); 
     Object[] args = jp.getArgs(); 
     if (args!=null && args[0] instanceof javax.jms.Message){ 
      Message msg = (Message)args[0]; 
      jmsTemplate.convertAndSend(errorDestination, msg); 
      log.info("Unexpected Error occured successfully routed to ErrorQ"); 
     }else 
      log.info("Unexpected Error occured failed to route to ErrorQ"); 
    } 
} 
+0

Quale versione primaverile stai usando? – tstorms

+0

@tstorms 3.0.6.RELEASE – c12

+0

Hai mai pensato di utilizzare l'ultima versione di primavera? In questo momento è 3.2.2.RELEASE. In questo modo, escludiamo possibili bug risolti. – tstorms

risposta

3

Sembra che l'NPE è gettato perché la connessione è nullo (this.target variabile).

Il collegamento è ottenuto dal DataSource poche righe prima (LazyConnectionDataSourceProxy.java):

// Fetch physical Connection from DataSource. 
this.target = (this.username != null) ? getTargetDataSource().getConnection(this.username, this.password) : getTargetDataSource().getConnection(); 

Googling ho trovato che driver Oracle JDBC può restituire un collegamento nullo nella seguente situazione (link):

ConnectionWaitTimeout

Specifica comportamento della cache quando viene richiesta una connessione e ci sono già connessioni MaxLimit attive. Se ConnectionWaitTimeout è maggiore di zero, ogni richiesta di connessione attende il numero di secondi specificato da o fino a quando non viene restituita una connessione alla cache . Se non viene restituita alcuna connessione alla cache prima del timeout , la richiesta di connessione restituisce null.

Default: 0 (nessun timeout)

Quindi, immagino, un timeout di connessione potrebbe spiegare il problema incoerente.

+0

Ho intenzione di aumentare ConnectionWaitTimeout a 30 secondi, a meno che non si disponga di un altro suggerimento per il valore di timeout? Potrei anche aumentare MaxLimit da 50 a 75. – c12

+0

Cambiare questi parametri dovrebbe ridurre il numero di timeout, ma dovresti comunque gestire le eccezioni nel codice dell'applicazione (ad esempio riprova, mostra messaggio all'utente ... dipende dalla tua applicazione) . –

+0

L'eccezione viene gestita quando il messaggio viene inserito in una coda di errore che può essere rielaborata. – c12

1

Hai già una transazioni applicata correttamente?

si può mostrare i file conifg di origine dati?

anche sembrare Slike si utilizza AOP con questi file a

myapp.api.listener.backoffice.StorableMessageListener.processNew(StorableMessageListener.java:136) 

myapp.api.listener.backoffice.StorableMessageListener.onMessage(StorableMessageListener.java:187) 
+0

Ho pubblicato la mia configurazione di primavera. Questa stessa configurazione funzionava da un anno nel nostro ambiente di produzione e nulla è cambiato rispetto alla configurazione. Potrebbe essere a livello di rete o di database, ma sfortunatamente non riesco a scavare molto in quelle aree. Qualche idea su come visualizzare le connessioni attive, forse ho raggiunto il limite massimo consentito da Glassfish. Qualche idea sul perché Spring avrebbe lanciato quell'eccezione? – c12

+0

Cosa fa il codice in StorableMessageListener? Sembra che si accenda grazie ad alcuni AOP ... – NimChimpsky

+0

È un ascoltatore JMS di Spring che sta elaborando i messaggi da una coda di messaggi OpenMQ e li memorizza in un database Oracle. – c12

Problemi correlati