2014-03-28 63 views
0

我有我的WebSphere Application Server,使用一個功能通過使用JMS發送消息到MQ上部署EAR,並且從另一個隊列。:如何使JMS消息發送到MQ完全提交?

ConnectionFactory cf = null; 
    InitialContext context = null; 
    String[] arrDatos_SR = null; 

    Connection conn = null; 
    Session session = null; 
    Queue queue = null; 
    Queue queue2 = null; 

    Destination dest = null; 
    Destination dest2 = null; 
    MessageConsumer consumer = null; 
    MessageProducer producer = null; 
    TextMessage message = null; 

    String comando = ""; 
    int tamanio = 0; 
    String tamanio2 = ""; 
    String cadena = ""; 

    try { 
     context = new InitialContext(); 
     cf = (ConnectionFactory) context.lookup(arrDatos[1].trim()); 
     conn = cf.createConnection(); 
     session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);  
     queue = (Queue) context.lookup(arrDatos[2].trim()); 
     queue2 = (Queue) context.lookup(arrDatos[3].trim()); 
     dest = (Destination) queue; 
     dest2 = (Destination) queue2; 

     producer = session.createProducer(dest); 


     // Create a text message using the queue session. 
     TextMessage textMessage = session.createTextMessage(); 

     textMessage.setText(arrDatos[4]); 

     textMessage.setJMSReplyTo(dest2); 
     textMessage.setJMSMessageID(arrDatos[6]); 
     textMessage.setJMSCorrelationID(arrDatos[7]); 
     producer.send(textMessage); 


    } catch (NamingException e) { 
     // TODO Auto-generated catch block 
     logger.error("MQSendReceive() - Exception e2 = " 
       + e, e); 
    } catch (JMSException e) { 
     // TODO Auto-generated catch block 
     logger.error("MQSendReceive() - Exception e2 = " 
       + e, e); 
    } 

     arrDatos[5] = arrDatos[5].trim(); 

     try{ 
      conn.start();  
      consumer = session.createConsumer(dest2); 
      Message receivedMessage = consumer.receive(Long.parseLong(arrDatos[5]) * 1000); 



      if(receivedMessage != null) 
      { 
       message = (TextMessage)receivedMessage; 
       comando = message.getText(); 
       comando = comando.trim(); 
       tamanio = comando.length(); 
       tamanio2 = StringUtils.leftPad(Integer.toString(tamanio), 9, '0'); 

       comando = StringUtils.rightPad(comando, Constantes.TAMANIO_RESPUESTA_DES_C1, ' '); 
       cadena = arrDatos[0] + comando + tamanio2; 
      } 
      else 
      { 
       comando = new String(); 
       comando = ""; 
       tamanio = comando.length(); 
       tamanio2 = StringUtils.leftPad(Integer.toString(tamanio), 9, '0'); 

       cadena = arrDatos[0] + comando + tamanio2; 
      } 

      arrDatos_SR = new String[2]; 
      arrDatos_SR[0] = cadena; 
      arrDatos_SR[1] = arrDatos[0]; 

     } 
     catch(Exception e) 
     { 
      logger.error("MQSendReceive() - Excepcion:" + e); 
     } 
     finally 
     { 
      try { 
       consumer.close(); 
       session.close(); 
       conn.close(); 
       context.close(); 
      } catch (JMSException e) { 
       // TODO Auto-generated catch block 
       logger.error("MQSendReceive() - Error desconectando de MQ - Excepcion:" + e); 
      } catch (NamingException e) { 
       // TODO Auto-generated catch block 
       logger.error("MQSendReceive() - Error desconectando de MQ - Excepcion:" + e); 
      } 

     } 

     return arrDatos_SR; 

被髮送的消息inmediately接收到消息到MQ隊列#1,MQ隊列#1然後被轉移到另一個MQ隊列#2,這是一個傳輸隊列到另一個MQ隊列#3。我使用Websphere MQ Administration GUI進行測試,將消息放入此隊列中,並順利傳輸。但是當我出於某種原因使用我的代碼時,發送不是立即發出的。相反,它是在接收結束後完成的(當超時到期或實際收到消息時)

有人可以告訴我爲什麼會發生這種情況?

UPDATE:(2014年3月31日),我忘了提,我使用的是@LocalBean,@Singleton和@TransactionManagement(TransactionManagementType.CONTAINER)上的註釋的EJB容器。通過從SO(http://goo.gl/JBSW7r)閱讀這篇文章,我意識到我有3個類構成整個連接,並且一個主要部分將所有這些類用作我使用公共方法的對象。我決定使用相同的註釋將這些類轉換爲EJB。我還嘗試將每種方法的@TransactionAttribute類型更改爲需要,不支持和強制一次,以測試它們中的某些是否有效。我也將會話線更改爲:

session = conn.createSession(true, Session.SESSION_TRANSACTED); 

結果看起來是一樣的。在MessageConsumer的超時間隔內收到消息時,消息仍然滯留在傳輸隊列中。

有人可以給我一些雖然這些?

回答

1

經過這麼多嘗試,我結束了刪除EJB。我用整個邏輯做了一個Web項目。我決定通過使用帶有while循環的線程來控制代碼的重複。我使用布爾變量來控制EAR啓動和關閉時的while循環的初始化和停止。

那麼,回到web應用程序,它的工作原理應該如此。我不知道爲什麼它會這樣,而不是其他,但我認爲現在沒問題。

2

根據您對問題的描述,我相信您提供的代碼正在EJB的上下文中執行,其中容器管理事務有效。在Java EE應用程序服務器中,JMS操作將由事務協調。這意味着發送實際上不會完成,直到事務在EJB方法結束時由容器提交。

儘管在Java EE應用程序服務器中創建會話時設置爲false,但會被忽略,並且會話將在任何有效的全局事務中註冊。

此問題的解決方案是確保JMS發送沒有事務執行。爲此,應該使用NOT_SUPPORTED事務類型來配置EJB方法。

+0

是的,我幾乎忘記提到這一點,對不起。它是一個EJB容器。這是一個Singleton會話Bean,具有LocalBean設置。我沒有指定交易類型。當我使用真正的Transacted選項測試會話時,它不起作用,因爲部署時會導致IllegalStateException:全局事務中不允許使用該方法。我認爲這是因爲服務器正在通過EJB容器來管理提交。所以可以將選項保留爲假,對嗎? – Xanathos

+0

我正在閱讀一些文章。首先,我的EJB使用另外3個類來建立DataQueue和MQ隊列之間的連接。因爲這些不是Session Beans,所以我認爲這可能是問題(因爲我讀的是:http://goo.gl/JBSW7r)所以我轉而使用Singleton Session Beans中的其他3個類(就像第一個類)。我還在主EJB中添加了TransactionManagement.CONTAINER和TransactionManagementType(對於main來說,REQUIRED是REQUIRED,對於實際連接的類來說是NOT SUPPORTED)。它仍然不起作用。難道我做錯了什麼? – Xanathos

0

雖然看起來OP通過將他的邏輯移動到Web模塊來獲得解決方法,但我認爲如果其他人需要使用EJB,我會添加一個潛在選項。

Alasdair的答案絕對是將EJB類型邏輯移回Web應用程序的首選方式。在創建新的EJB 3.0項目並定義一個發送消息並等待來自Websphere MQ的回覆的bean時,我們剛剛遇到了此問題。我們發現我們確實已經在開始時定義了一個事務類型爲Container的會話bean,這在前面提到的確切原因是失敗的。

將交易類型切換爲Bean然而,爲我們解決了這個問題。它仍然允許會話bean保留一些事務屬性,但也讓JMS發送提交的消息。