2016-02-04 2 views
1

Я разрабатываю веб-приложение с AngularJs как front-end и Spring + Hibernate как сервисный уровень. Сервисный уровень имеет набор REST API, которые потребляются AngularJs. Передняя часть приложения не имеет серьезных проблем. Но на уровне обслуживания я столкнулся с некоторыми проблемами параллелизма. Для некоторых сценариев я должен выполнять параллельные асинхронные вызовы с теми же API REST из той же самой http-сессии. Когда я это делаю, бывают случаи, когда я получаю вышеуказанную ошибку. Фактически, ошибка постоянно меняется каждый раз. Иногда я также получаю NULLPointerException в Query.List(). Иногда я получаю исключение TransactionResourceAlreadyClosed. Ниже приведены различные конфигурации и фрагменты кода.org.hibernate.AssertionFailure: возможный не-потоковый доступ к сеансу

web.xml

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>WEB-INF/config/fs-cxf-serverContext.xml,WEB-INF/config/fs-spring-jpa-config.xml,WEB-INF/config/security-beans.xml</param-value> 
</context-param> 

<listener> 
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> 
</listener> 
<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 

<filter> 
    <filter-name>CorsFilter</filter-name> 
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class> 
    <init-param> 
     <param-name>cors.allowed.origins</param-name> 
     <param-value>*</param-value> 
    </init-param> 
    <init-param> 
     <param-name>cors.allowed.headers</param-name> 
     <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Access-Control-Allow-Origin</param-value> 
    </init-param> 
    <init-param> 
     <param-name>cors.exposed.headers</param-name> 
     <param-value>Access-Control-Allow-Origin</param-value> 
    </init-param> 
    <init-param> 
     <param-name>cors.allowed.methods</param-name> 
     <param-value>GET, POST, PUT, DELETE, OPTIONS, HEAD</param-value> 
    </init-param> 
</filter> 
<filter-mapping> 
    <filter-name>CorsFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

<filter> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

<servlet> 
    <description>Servlet to Initialize and shutdown the Scheduler</description> 
    <servlet-name>QuartzInitializer</servlet-name> 
    <servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class> 
    <init-param> 
     <param-name>config-file</param-name> 
     <param-value>quartz.properties</param-value> 
    </init-param> 
    <init-param> 
     <param-name>shutdown-on-unload</param-name> 
     <param-value>true</param-value> 
    </init-param> 
    <init-param> 
     <param-name>start-scheduler-on-load</param-name> 
     <param-value>true</param-value> 
    </init-param> 
    <load-on-startup>2</load-on-startup> 
</servlet> 
<servlet> 
    <servlet-name>CXFServlet</servlet-name> 
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

<servlet-mapping> 
    <servlet-name>CXFServlet</servlet-name> 
    <url-pattern>/services/*</url-pattern> 
</servlet-mapping> 

<resource-ref> 
    <res-ref-name>jdbc/foodsafetyDS</res-ref-name> 
    <res-type>javax.sql.DataSource</res-type> 
    <res-auth>Container</res-auth> 
    <res-sharing-scope>Shareable</res-sharing-scope> 
</resource-ref> 

Конфигурация JPA

<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 
xmlns:tx="http://www.springframework.org/schema/tx" 
xmlns:task="http://www.springframework.org/schema/task" 
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 
    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd"> 

<!-- Hibernate session factory --> 
<bean id="sessionFactory" 
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
    <property name="configLocation" value="classpath:hibernate.cfg.xml" /> 
    <property name="entityInterceptor"> 
     <bean class="com.cts.foodSafety.interceptor.AuditLogInterceptor"/> 
    </property> 
</bean> 

<bean id="transactionManager" 
    class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
</bean> 

<bean id="persistenceAnnotation" 
    class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> 

<tx:annotation-driven transaction-manager="transactionManager" /> 
<task:annotation-driven/> 

hibernate.cfg.xml

<hibernate-configuration> 
<session-factory> 
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> 
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> 
    <property name="hibernate.connection.datasource">java:comp/env/jdbc/foodsafetyDS</property> 
    <property name="hbm2ddl.auto">update</property> 
    <property name="show_sql">false</property> 

    <!-- Mapping with model class containing annotations --> 

Я создал простой контроллер отдыха с использованием CXF. REST конечной точки, как показано ниже

@Path("/units") 
@Produces(MediaType.APPLICATION_JSON) 
public interface UnitService extends Serializable { 

@GET 
@Path("/getGraphData/{type}") 
@Produces(MediaType.APPLICATION_JSON) 
public UnitServiceBean getGraphData(@PathParam("type") String type) 
     throws FoodSafetyException; 

}

реализации контроллера, как показано ниже

xxxServiceImpl.java

@Service("unit") 
@Transactional 
public class xxxServiceImpl implements xxxService { 

private static final long serialVersionUID = 1L; 

@Autowired 
xxxDelegate xxxDelegate; 

@Override 
public UnitServiceBean getGraphData(String type) throws FoodSafetyException { 
    UnitServiceBean bean = new UnitServiceBean(); 

    List<String[]> data = unitDelegate.getGraphData(type); 
    .... 
    .... 
    return bean; 
} 

делегат вызывает DAO. (На данный момент мы не представили бизнес-объект). Реализация DAO как ниже

@Component 
public class UnitDAOImpl extends FoodSafetyDAO implements UnitDAO { 
@Override 
public List<String[]> getGraphData(String type) { 
    List<String[]> data = new ArrayList<String[]>(); 
    Map<String, List<UnitReadingEntity>> readings = new HashMap<String, List<UnitReadingEntity>>(); 

    SimpleDateFormat df = CommonConstants.TIME_FORMATTER; 

    // Get all the Units 
    Query query = getSession().getNamedQuery(
      QueryConstants.FIND_UNITS_BY_TYPE); 
    query.setParameter(QueryConstants.TYPE, type); 
    List<UnitEntity> units = (List<UnitEntity>) query.list(); 
    if (units != null && units.size() != 0) { 
     ..... 
     ..... 

     for (UnitEntity unit : units) { 
      Calendar cal1 = Calendar.getInstance(); 
      cal1.add(Calendar.DAY_OF_YEAR, -1); 
      query = getSession().getNamedQuery(
        QueryConstants.FIND_READING_BY_UNIT_TIME).setLong(
        QueryConstants.UNIT_ID, unit.getUnitId()); 

      List<UnitReadingEntity> rr = query.list(); 
      ... 
      ... 
     } 
    } 

    return data; 
} 

Теперь, когда я вызываю службу REST «getGraphData» один раз Почтальон и т.д. он прекрасно работает без каких-либо проблем. Но когда я имитировать одновременный вызов этого покоя службы с помощью я получаю следующее сообщение об ошибке

Caused by: org.hibernate.AssertionFailure: possible non-threadsafe access to the session 
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:130) 
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1108) 
at org.hibernate.loader.Loader.processResultSet(Loader.java:964) 
at org.hibernate.loader.Loader.doQuery(Loader.java:911) 
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:342) 
at org.hibernate.loader.Loader.doList(Loader.java:2526) 
at org.hibernate.loader.Loader.doList(Loader.java:2512) 
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2342) 
at org.hibernate.loader.Loader.list(Loader.java:2337) 
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:495) 
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:356) 
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:195) 
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1269) 
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101) 
at com.cts.foodSafety.model.dao.impl.UnitDAOImpl.getGraphData(UnitDAOImpl.java:255) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
at java.lang.reflect.Method.invoke(Method.java:597) 
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:51) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:42) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) 
at com.sun.proxy.$Proxy51.getGraphData(Unknown Source) 
at com.cts.foodSafety.delegate.UnitDelegate.getGraphData(UnitDelegate.java:39) 
at com.cts.foodSafety.delegate.UnitDelegate$$FastClassByCGLIB$$aac35d0d.invoke(<generated>) 
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:51) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:42) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631) 
at com.cts.foodSafety.delegate.UnitDelegate$$EnhancerByCGLIB$$75af66.getGraphData(<generated>) 
at com.cts.foodSafety.service.impl.UnitServiceImpl.getGraphData(UnitServiceImpl.java:108) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
at java.lang.reflect.Method.invoke(Method.java:597) 
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:51) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:42) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:55) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96) 
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260) 
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91) 
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) 
at com.sun.proxy.$Proxy72.getGraphData(Unknown Source) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
at java.lang.reflect.Method.invoke(Method.java:597) 
at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:180) 
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96) 

Клиент, который я использовал, чтобы сделать параллельный запрос, как показано ниже

public class RestClient implements Runnable{ 

private String i; 

public RestClient(String x) { 
    i=x; 
} 
public static void main(String[] args) { 

    for(int i =1;i<=2;i++) { 
     Thread t = new Thread(new RestClient(String.valueOf(i))); 
     t.start(); 
    } 
} 

@Override 
public void run() { 
    System.out.println("started " + i); 
     try { 

      URL url = new URL(" http://localhost:8080/fs/services/units/getGraphData/Freezer"); 
      HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
      conn.setRequestMethod("GET"); 
      conn.setRequestProperty("Accept", "application/json"); 

      if (conn.getResponseCode() != 204) { 
       throw new RuntimeException("Failed : HTTP error code : " 
         + conn.getResponseCode()); 
      } 

Все указатели/предложения? Я провел много материалов по сессиям и управлению транзакциями в Spring + hibernate. Но я не могу решить эту проблему.

+0

Вы должны начать новую сессию/транзакцию Hibernate, если вы делегируете некоторую работу другому потоку. –

+0

@Dragan Bozanovic Я не делегирую работу новой теме. Я делаю одну и ту же работу дважды (одновременно) в двух потоках. Я знаю, что сеанс hibernate не является потокобезопасным, поэтому совместное использование сеансов по потокам является строгим NO-NO – user1996183

+0

Что такое метод getSession? –

ответ

0

Я думаю, что если вы используете Hibernate как это, то вы должны получить сеанс, вызвав вместо этого getSession(false), чтобы убедиться, что сеанс привязан к транзакции.

Это объясняется в главе Implementing Spring-based DAOs without callbacks in Spring documentation: такого код, как правило, проходит фальшив, как стоимости (..) методы getSession allowCreate аргумент, для обеспечения исполнения работы в рамках транзакции (что позволяет избежать необходимости закрыть возвращенную сессию, так как его жизненный цикл управляется транзакцией).

Смежные вопросы