2016-09-21 2 views
0

EJB 컨테이너에서 실행되는 일부 Java 코드 (JMS 메시지 전달으로 시작됨)가 있고 그 코드가 다른 JMS 메시지를 동일한 대기열에 넣는 경우 해당 메시지가 전달 될 때까지는 어떻게 방지합니까? 그것을 쫓아 낸 코드가 완료되었고 트랜잭션이 커밋 되었습니까? 기본적으로 트랜잭션 동시성 문제가 발생합니다. JMS 메시지 A에 의해 시작되는 코드가 있습니다.이 코드는 몇 가지 작업을 수행 한 다음 데이터베이스 삽입 작업을 수행합니다 (컨테이너 관리 EJB 트랜잭션으로 인해이 코드가 모두 실행될 때까지 커밋하지 않습니다). 그런 다음 큐에 방금 삽입 된 DB 행의 ID가있는 메시지 (메시지 B)를 넣습니다. 그런 다음 잠시 시간이 걸리는 동일한 트랜잭션에서 다른 작업을 수행합니다.JMS 및 Java EE 트랜잭션

데이터베이스 행의 ID가있는이 메시지 바로 다음에 큐에 넣어지면 메시지 A에 의해 시작된 코드에 의해 삽입 된 해당 행을 쿼리하려고하는 코드가 실행됩니다. 문제는 그 행을 삽입 한 코드가 아직 실행 중이며 트랜잭션이 아직 커밋되지 않았다는 것입니다. 따라서 문제의 데이터베이스 행은 쿼리 할 DB에 없습니다. 결과적으로 메시지 B에 의해 시작된 코드는 필요한 DB 행을 찾을 수 없기 때문에 오류가 발생합니다.

어떻게 방지합니까? Java EE 컨테이너에서 JMS 및 트랜잭션에 대한 여러 시간 동안의 연구를 수행했습니다. 필자가 읽은이 자습서에서는 메시지를 받고 동일한 트랜잭션에서 회신을 보낼 수 없다는 것을 말합니다. 모든 트랜잭션이 완료 될 때까지 컨테이너가 메시지를 큐에 커밋하지 않아야합니까?

이 질문이 왜곡되면 죄송합니다. 나는 최선을 설명하려고 노력하고있다. 여기에 붙여 넣기에는 너무 많은 코드가 있습니다. 하지만 환경은 WildFly 8.1이며 실행 코드는 Stateless EJB 내부에 있으며 JPA는 데이터베이스 액세스에 사용되며 메시지는 항목이 아닌 대기열에 있습니다. 충분한 정보가 있기를 바랍니다. 내가 연결을 한 번만 초기화 되었기 때문에,

@Resource(mappedName = "java:/JmsXA") 
XAConnectionFactory connectionFactory; 

이이 일을 처음 작동을 중지했다 :

@Resource(mappedName = "java:/ConnectionFactory") 
ConnectionFactory connectionFactory; 

XA 연결 팩토리 :

// How factory and queues are declared in java code: 

@Resource(mappedName = "java:/ConnectionFactory") 
ConnectionFactory connectionFactory; 

@Resource(mappedName = "java:jboss/exported/jms/queue/quequeA") 
Queue queueA; 

@Resource(mappedName = "java:jboss/exported/jms/queue/quequeB") 
Queue queueB; 

//Sending message: 

TextMessage message = session.createTextMessage("some message goes here"); 
MessageProducer producer = session.createProducer(queueA); // samething for queueB 
producer.send(message); 

// how queues are configured in WidlFly's standalone.conf : 

<jms-queue name="quequeA"> 
    <entry name="queue/quequeA"/> 
    <entry name="java:jboss/exported/jms/queue/quequeA"/> <!-- same thing for queueB --> 
</jms-queue> 

<address-setting match="jms.queue.quequeA"> 
    <dead-letter-address>jms.queue.DLQ</dead-letter-address> 
    <redelivery-delay>5000</redelivery-delay> 
    <max-delivery-attempts>1</max-delivery-attempts> 
    <max-size-bytes>10485760</max-size-bytes> 
    <page-size-bytes>1048576</page-size-bytes> 
    <address-full-policy>PAGE</address-full-policy> 
    <message-counter-history-day-limit>10</message-counter-history-day-limit> 
</address-setting> 

// creating connection and session: 
connection = connectionFactory.createConnection(); 
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // note: the application is running in the Java EE web/EJB environment, so both "fasle" and auto_acknowledge arguments shoudl be ignored according to the javadoc. I'm trying to use container-managed transactions for everything 
+0

메시지의 모든 이야기와 함께, 당신은 JMS가 아니라 JMX를 확실히 의미합니까? – Nicholas

+0

죄송합니다. JMS입니다. – Creature

+0

http://stackoverflow.com/questions/13890287/jms-transaction – home

답변

0

나는 일반 연결 팩토리를 변경했다 EJB 당 @PostConstruct를 만들고 @PreDestroy 주석이 달린 메소드에서이를 닫습니다. 그래서 그 외에도 각 메서드의 시작 부분으로 연결 및 세션 생성을 이동하고 각 메서드의 끝에서 닫아야했습니다.