2016-11-24 1 views
0

메시지를 수신하고 상태를 DB로 업데이트하는 MQ 수신기가 있습니다. 나는 Hibernate 세션이 Spring에 의해 관리되는 환경을 가지고있다.최대 절전 모드 업데이트를 수행 할 때의 불일치

다음은 MQ 리스너 구성입니다. MQ 메시지를 처리하는 자바 말에

 <bean id="queue" class="com.ibm.mq.jms.MQQueue"> 
      <constructor-arg value="queuename" /> 
     </bean> 
     <bean id="listenerBean" class="com.mypackage.Listener"> 
       <property name="service" ref="myService" /> 
     </bean> 
     <bean id="listener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter"> 
       <constructor-arg><ref bean="listenerBean"/></constructor-arg> 
     </bean> 
     <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> 
       <property name="connectionFactory" ref="connectionFactory" /> 
       <property name="destination" ref="queue" /> 
       <property name="messageListener" ref="listener" /> 
       <property name="exceptionListener" ref="exceptionListener" /> 
       <property name="sessionTransacted" value="true" /> 
       <property name="autoStartup" value="true" /> 
     </bean> 

,

public class Listener implements MessageDelegate{ 

     public MyService service; 

     @Override 
     public void handleMessage(Serializable message) { 
       service.process(message); 
     } 
} 

서비스 클래스의 처리 방법은 DB를 업데이트 할 수있는 DAO 메소드를 호출합니다.

다음은 Spring sessionFactory bean org.springframework.orm.hibernate3.LocalSessionFactoryBean에 사용되는 최대 절전 모드 속성입니다.

<property name="hibernateProperties"> 
      <props> 
        <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> 
        <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> 
        <prop key="hibernate.cache.use_second_level_cache">true</prop> 
        <prop key="hibernate.cache.use_query_cache">true</prop> 
        <prop key="hibernate.show_sql">false</prop> 
        <prop key="hibernate.generate_statistics">true</prop> 
        <prop key="hibernate.cache.provider_configuration_file_resource_path">ehcache_db_custom.xml</prop> 
      </props> 
    </property> 

이 sessionFactory에 내 DAO 빈에 주입하고 난 MQ 메시지로부터 얻을 나는 고유 한 값을 기준으로 콩을 얻을 수 기준 API를 사용하고이 session를 사용 sessionFactory.getCurrentSession()

를 사용하여 내 세션을 얻을 고유 한 결과를 얻으면 상태를 성공으로 변경하고 sessionFactory.getCurrentSession()을 호출하여 session을 얻고 session.update()을 호출하여 DB를 업데이트하십시오.

hbm 파일을 사용하면서 bean에 대한 주석이 없습니다. 일대 다 또는 다 대일 매핑이없는 단순한 bean입니다. 주석은 @Transactional입니다.

다음은 업데이트 스 니펫입니다. 저는 Spring이 트랜잭션을 처리한다고 생각합니다.

Session session = sessionFactory.getCurrentSession(); 
    if(session != null && bean != null) { 
     session.update(bean); 
    } 

은 내가 DB 업데이트가 실패 할 때마다 DB가 성공적으로 업데이트하고 예외 처리에 대한 (나 추가, log4j에) 로거가 있습니다.

이상한 부분이 있습니다.

로그가 최대 절전 모드에서 발생하는 예외를 표시하지 않고 로그 표시 DB가 성공적으로 업데이트되는 다중 스레드 환경에서 시나리오를 발견했습니다. 그러나 상태는 업데이트되지 않습니다. 이것은 일부 레코드에만 발생하며 전체에 대해서는 발생하지 않습니다. 성공적으로 업데이트 된 레코드가 있습니다. 데이터 관련 문제를 찾을 수 없습니다.

JUnit을 사용하여 업데이트하지 못한 레코드 중 하나를 실행했을 때 성공적으로 업데이트되었습니다.

설정이 끝나면 아무 것도 알려주지 않습니까?

+0

MQ 리스너 코드를 추가하고 구성된 리스너 수를 알려줄 수 있습니까? – developer

+0

@javaguy 질문에 MQ 리스너 코드가 업데이트되었습니다. 8 개의 JVM에 2 개의 서버에 8 개의 리스너가 분산되어 있습니다. – Prabhat

답변

0

기본적으로 다중 스레드 JMS 응용 프로그램에서 사용자가 여러 스레드로 수신 대기하는 경우 메시지가 생산자가 생성 한 순서를 잃어 버리고 잘못된 데이터베이스의 업데이트 (예외없이 애플리케이션을 신중하게 설계하지 않은 경우 우리는 같은 문제를 다시 겪게됩니다).

그래서 문제를 해결하려면 업데이트 할 레코드가 실제로 올바른지 확인하기 위해 데이터베이스 측에서 비즈니스 로직을 가져야합니다 (이 트랜잭션을 적절한 트랜잭션으로 처리해야합니다. 잠금). 예를 들어, 응용 프로그램에 이 증가하는 순서로 데이터베이스 테이블에 products 테이블을 보유하고있는 경우 새 메시지가 더 높은 가치의 제품으로 표시 될 때만 새 업데이트를 수행해야하는지 확인해야합니다.

또 다른 해결책은 어댑터 (단일 스레드 여야 함)와 같은 항목 계층을 생성하고 일부 비즈니스 로직을 사용하여 시퀀스 번호를 생성하는 것입니다 (각 product_type에 시퀀스가 ​​있음). 데이터베이스 중에 해당 시퀀스 번호를 확인하십시오 최신 정보. 시퀀스 번호가 이전 값보다 작 으면 최신 메시지가 아니므로 메시지를 무시해야합니다. 즉, 최신 메시지가 이미 데이터베이스로 업데이트되었습니다.

+0

기본적으로 MQ 메시지에서 수신 한 고유 ID는 프로세스의 일부입니다. 이 레코드는 1 일 또는 2 일 전에 '신규'상태로 DB에 삽입되었으므로 확실히 DB에 있어야합니다. 해당 레코드가 'Completed'상태로 업데이트되는 한 MQ 메시지가 소비되는 순서는 신경 쓰지 마십시오. – Prabhat

+0

새 상태와 완료 상태 이외의 다른 상태는 무엇입니까? – developer

+0

'진행 중'이지만 응용 프로그램마다 다릅니다. 기본적으로 'New'로 변경 한 후 프로세스가 진행되고 'In Progress'로 업데이트되면 지연이 발생합니다. 그런 다음 응용 프로그램이 MQ에서 메시지를 가져 와서 상태를 'Completed'로 갱신합니다. MQ에서 메시지를 수신 했더라도 '진행 중'상태의 일부 레코드가 표시됩니다. – Prabhat