首页 文章

Spring tomee JTA交易

提问于
浏览
1

我一直在努力构建一个非常简单的应用程序,该应用程序使用spring,hibernate和JMS进行部署 . 我相信我的所有配置都是正确的(有mysql xa数据源和xa活动的mq连接工厂)但事情并没有像我期望的那样工作 . 目前我有一个简单的服务,使用注入的实体管理器写入,然后在一个注释为事务性(spring注释)的方法中推送到JMS,但我的消息监听器在 Spring 天提交事务之前传递这些消息 .

我已经尝试过直接使用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>

我已经尝试了几种方法来包括不使用XAConnectionFactory和JMSTemplate配置为sessionTransacted而不是,删除JMSTemplate并从connectionFactory创建连接/会话/ 生产环境 者/消息,但我每次都遇到问题 . 通过从ConnectionFactory手动创建连接/会话/生成器/消息,我注意到我尝试写入数据库的20个项目然后在服务事务完成之前发送到另一个JMS队列开始被读取 .

据我所知,一切都配置正确(虽然我肯定是错的,因为这是从很多地方拉出来的) . 我的目标是能够使用JMSTemplate而不是自己手动创建连接/会话/等,但我不知道为什么会发生这种情况,所以任何想法都非常感激 .

我还提到了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

我进一步加快了 Loggers 作

[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 [org.springframework.jms.connection.JmsResourceHolder@81032a4] for key [org.apache.activemq.ra.ActiveMQConnectionFactory@5ee0c65d] to thread [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1]

[org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [org.springframework.jms.connection.JmsResourceHolder@eaebd86] for key [org.apache.activemq.ra.ActiveMQConnectionFactory@5ee0c65d] 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 [org.springframework.jms.connection.JmsResourceHolder@81032a4] for key [org.apache.activemq.ra.ActiveMQConnectionFactory@5ee0c65d] 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 [org.springframework.jms.connection.JmsResourceHolder@81032a4] for key [org.apache.activemq.ra.ActiveMQConnectionFactory@5ee0c65d] 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是一个通过id检索实体然后打印内容的bean .

我不是百分百肯定如何阅读本文,但有趣的是DMLC#1-1在DMLC#0-1上开始新的事务后很好地提交,但DMLC#0-1看到了该消息 . 我原本以为DMLC#0-1需要启动一个新的事务才能看到这个OR,因为他收到了JMS消息,实体也应该持久化到数据库 .

我的持久化bean的内容@Override @Transactional public void onMessage(消息消息){TextMessage msg =(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();
    }

}

我的印花 beans 的内容

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获得,运行vanilla Tomee 1.7.1,并在tomee / lib目录中添加必要的hibernate jar .

我在这里真的很茫然,没有人在Tomee用Spring运行JTA交易吗?

1 回答

  • 0

    经过大量的调试后发现失败不在JTA实现中,但更多的是我对JTA的理解 . 虽然JTA确保两个事务都成功提交,但它并不强制执行这些事务的命令 . 答案最终由StéphaneNicoll在这里提供https://jira.spring.io/browse/SPR-12535 .

相关问题