2014-12-05 109 views
1

我一直在努力嘗試構建一個非常簡單的應用程序,使用spring,hibernate和JMS來部署。我相信我的所有配置都是正確的(具有mysql xa數據源和xa活動mq連接工廠),但事情並不像我所期望的那樣工作。目前我有一個簡單的服務,使用注入的實體管理器寫入,然後在一個被註釋爲事務性(Spring註釋)的方法中推送到JMS,但是我的消息偵聽器在事務提交之前正在傳遞這些消息。Spring + tomee JTA交易

我試過直接使用JMS模板和xa連接工廠,但都沒有正常工作。該模板使用從jndi收到的jta事務管理器進行配置。任何想法爲什麼要看JMS發送的提示都不參與與數據庫寫入相同的事務?

Spring配置文件:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:jee="http://www.springframework.org/schema/jee" 
    xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr" 
    xmlns:task="http://www.springframework.org/schema/task" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:util="http://www.springframework.org/schema/util" 
    xmlns:encryption="http://www.jasypt.org/schema/encryption" 
    xmlns:jms="http://www.springframework.org/schema/jms" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
              http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd 
              http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd 
              http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd 
              http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd 
              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd 
              http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd 
              http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd 
              http://www.jasypt.org/schema/encryption http://www.jasypt.org/schema/encryption/jasypt-spring31-encryption-1.xsd 
              http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.1.xsd" 
    default-autowire="byType" default-lazy-init="false"> 

    <context:component-scan annotation-config="false" base-package="org.superbiz" /> 

    <bean class="org.springframework.orm.jpa.DefaultJpaDialect" /> 
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" /> 

    <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" /> 
    <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" /> 
    <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"> 
      <property name="alwaysUseJndiLookup" value="false" /> 
      <property name="jndiFactory" > 
        <ref local="jndiFactory"/> 
      </property> 
    </bean> 

    <bean id="jndiFactory" class="org.springframework.jndi.support.SimpleJndiBeanFactory"> 
      <property name="resourceRef" value="true" /> 
    </bean> 

    <bean id="PrintTemplate" class="org.springframework.jms.core.JmsTemplate"> 
      <property name="connectionFactory"> 
        <ref local="jmsFactory" /> 
      </property> 
      <property name="defaultDestinationName" value="resources/jms/PrintQueue" /> 
      <property name="deliveryPersistent" value="true"/> 
      <!-- <property name="sessionTransacted" value="true"/> --> 
      <!-- <property name="sessionAcknowledgeMode" value="0"/> --> 
    </bean> 

    <bean id="PersistTemplate" class="org.springframework.jms.core.JmsTemplate"> 
      <property name="connectionFactory"> 
        <ref local="jmsFactory" /> 
      </property> 
      <property name="defaultDestinationName" value="resources/jms/PersistQueue" /> 
      <property name="deliveryPersistent" value="true"/> 
      <!-- <property name="sessionTransacted" value="true"/> --> 
      <!-- <property name="sessionAcknowledgeMode" value="0"/> --> 
    </bean> 

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"> 
      <property name="defaultPersistenceUnitName" value="movie-unit" /> 
      <property name="persistenceContexts"> 
        <map> 
          <entry key="movie-unit" value="persistence/movie-unit" /> 
        </map> 
      </property> 
    </bean> 

    <context:component-scan base-package="org.superbiz.ejb" annotation-config="false"> 
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
    </context:component-scan> 

    <jee:jndi-lookup id="jmsFactory" jndi-name="resources/jms/ConnectionFactory" expected-type="javax.jms.ConnectionFactory" /> 

    <tx:jta-transaction-manager /> 

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

    <bean id="printBean" class="org.superbiz.mdb.PrintBean"/> 
    <bean id="persistBean" class="org.superbiz.mdb.PersistBean"/> 

    <jms:listener-container container-type="default" connection-factory="jmsFactory" cache="none" transaction-manager="transactionManager" concurrency="1" receive-timeout="1000" prefetch="-1"> 
      <jms:listener destination="resources/jms/PrintQueue" ref="printBean" /> 
      <jms:listener destination="resources/jms/PersistQueue" ref="persistBean" /> 
    </jms:listener-container> 

</beans> 

tomee.xml(從http://tomee-openejb.979440.n4.nabble.com/MDB-doesn-t-read-messages-td4666169.html拼湊)

<Resource id="ActiveMQResourceAdapter" type="ActiveMQResourceAdapter"> 
    BrokerXmlConfig=broker:(vm://localhost) 
</Resource> 

<Resource id="resources/jms/ConnectionFactory" type="javax.jms.ConnectionFactory"> 
    ResourceAdapter = ActiveMQResourceAdapter 
</Resource> 

<Resource id="resources/jms/XAConnectionFactory" class-name="org.apache.activemq.ActiveMQXAConnectionFactory"> 
    BrokerURL = vm://localhost 
    ResourceAdapter = ActiveMQResourceAdapter 
</Resource> 

<Resource id="resources/jms/PrintQueue" type="javax.jms.Queue"/> 
<Resource id="resources/jms/PersistQueue" type="javax.jms.Queue"/> 

<Resource id="MySQL Database" type="DataSource"> 
    JdbcDriver com.mysql.jdbc.jdbc2.optional.MysqlXADataSource 
    JdbcUrl jdbc:mysql://localhost/test 
    UserName test 
</Resource> 

我試過幾種方法,包括不使用與JmsTemplate中XAConnectionFactory配置爲sessionTransacted和不是,刪除JMSTemplate並從connectionFactory創建連接/會話/生成器/消息,但每次都遇到問題。通過從ConnectionFactory手動創建連接/會話/生產者/消息,我注意到我嘗試寫入數據庫的20個項目然後發送到另一個JMS隊列,在服務事務完成之前開始讀取。

據我可以告訴一切正確配置(雖然我可以肯定是錯誤的,因爲這是從很多地方拉)。我的目標是能夠使用JMSTemplate,而不是自己手動創建連接/會話/ etc,但是我爲此感到茫然,因爲在這一點上這是發生的,所以任何想法都非常感謝。

我也碰到了Spring的JtaTransactionManager的記錄了,我看到下面的情況發生時,@Transactional方法被調用

DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.superbiz.ejb.Movies.send]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' 
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit 

然後,我看到了我的MDB代碼試圖檢索從項目entityManager(它會間歇地工作/失敗)。當它成功我看到這個

printing from MDB: director: director0title: title0year: 0 
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit 
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.springframework.jms.listener.DefaultMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 

當它失敗我看到這個

/***************** BROKEN ***************/ 
/*******************435265*****************/ 
/***************** BROKEN ***************/ 
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit 
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.springframework.jms.listener.DefaultMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 

我進一步在這種情況下拍成記錄

[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.springframework.jms.listener.DefaultMessageListenerContainer#1]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 

**bold** [org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.springframework.jms.listener.DefaultMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 

[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Initializing transaction synchronization 

[org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Initializing transaction synchronization 

[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [[email protected]] for key [[email protected]] to thread [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] 

[org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [[email protected]] for key [[email protected]] to thread [org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] 

[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Participating in existing transaction 
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.interceptor.TransactionInterceptor - Getting transaction for [org.superbiz.mdb.PersistBean.onMessage] 
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Retrieved value [[email protected]] for key [[email protected]] bound to thread [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] 
Persisted finished, but not yet committed 
Leaving persist, should commit 
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.interceptor.TransactionInterceptor - Completing transaction for [org.superbiz.mdb.PersistBean.onMessage] 
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.jta.JtaTransactionManager - Triggering beforeCommit synchronization 
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.jta.JtaTransactionManager - Triggering beforeCompletion synchronization 
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Removed value [[email protected]] for key [[email protected]] from thread [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] 
**bold** [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit 

Entering print 
/***************** BROKEN ***************/ 
/*******************597852*****************/ 
/***************** BROKEN ***************/ 

使用DefaultMessageListenerContainer#1-1我的persist bean和0-1是一個bean,它通過id檢索實體,然後打印內容。

我不是百分百肯定如何閱讀這個,但是對我來說很有意思,DMLC#1-1在DMLC#0-1上開始一個新的事務後很好地提交,但是DMLC#0-1看到信息。我會認爲DMLC#0-1需要啓動一個新的事務才能看到這個OR,因爲他收到了JMS消息,這個實體也應該保存到數據庫中。

我的堅持豆 @Override @Transactional 公共無效的onMessage(消息信息){ 的TextMessage味精=(TextMessage的)消息的內容; int x;

try { 
     x = Integer.parseInt(msg.getText()); 
     Movie movie = new Movie("director" + x, "title" + x, x); 
     entityManager.persist(movie); 
     final long id = movie.getId(); 
     template.send(new MessageCreator() { 
      @Override 
      public Message createMessage(Session session) throws JMSException { 
       return session.createTextMessage(Long.toString(id)); 
      } 
     }); 
     System.out.println("Persisted finished, but not yet committed"); 
     System.out.println("Leaving persist, should commit"); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

} 

我打印豆

public void onMessage(Message message) { 
    System.out.println("Entering print"); 
    final TextMessage textMessage = (TextMessage) message; 

    try { 
     long id = Long.parseLong(textMessage.getText()); 
     Movie movie = entityManager.find(Movie.class, id); 
     if(movie == null){ 
      System.out.println("/***************** BROKEN ***************/"); 
      System.out.println("/*******************" + id + "*****************/"); 
      System.out.println("/***************** BROKEN ***************/"); 

     } else { 
      System.out.println("updating: "+ movie); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

} 

整個應用程序可在https://github.com/jej2003/simple-spring,運行香草Tomee 1.7.1與添加到tomee/lib目錄必需的Hibernate jar文件的內容。

我真的不知所措,沒有人在Tomee與Spring一起運行JTA事務嗎?

+0

當你問這樣的問題時,你需要顯示你的配置,並提供更多的信息 - 「...既不能正常工作......」,這樣的評論也不會削減它;抱歉。另外,打開「TRACE」級日誌記錄將會暴露很多信息。如果你無法從'TRACE'日誌中找出它,將它們發佈到某個地方。 – 2014-12-06 00:08:18

回答

0

經過大量調試後發現失敗並不在JTA實現中,但更多的是我對JTA的一般理解。雖然JTA確保這兩個交易將成功提交,但它並不強制執行明顯的這些交易的訂單。最終的答案是StéphaneNic​​oll在這裏提供的https://jira.spring.io/browse/SPR-12535