5

我正在将 Spring 3 与 JPA 一起使用,并且在我的 Web 应用程序中看到一个间歇性问题。我有 JPA EntityManager 的包装器,它调用底层的 EntityManager crud 方法。我有时在打电话时看到 NPEentityManager.persist(object);它看起来数据库连接丢失但我不是 100% 是什么原因。任何人都对可能导致以下异常的原因有任何详细信息?

春季版:3.0.6.RELEASE

Spring 3 LazyConnectionDataSourceProxy.java 第 416 行:

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

例外:

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

弹簧配置:

 <?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 错误处理程序:

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");
    }
}
4

2 回答 2

3

似乎 NPE 被抛出,因为连接为空(变量 this.target)。

连接是从前几行的 DataSource 获得的(LazyConnectionDataSourceProxy.java):

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

谷歌搜索我发现Oracle JDBC驱动程序在以下情况下可能会返回一个空连接(链接):

连接等待超时

指定请求连接并且已经有 MaxLimit 连接处于活动状态时的缓存行为。如果 ConnectionWaitTimeout 大于零,则每个连接请求都会等待指定的秒数或直到连接返回到缓存。如果在超时之前没有将连接返回到缓存,则连接请求返回 null。

默认值:0(无超时)

所以,我想,连接超时可以解释你不一致的问题。

于 2013-05-14T13:25:17.623 回答
1

您是否正确应用了交易?

你能显示数据源的配置文件吗?

此外,您似乎正在将 AOP 与这些文件一起使用

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

myapp.api.listener.backoffice.StorableMessageListener.onMessage(StorableMessageListener.java:187)
于 2013-05-14T12:21:07.830 回答