Announcement Announcement Module
Collapse
No announcement yet.
XA (Atomikos + AMQ + Hibernate) Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • XA (Atomikos + AMQ + Hibernate)

    The need is obvious. We have to send a JMS message (via jmsTemplate) and make an insert (via hibernateTemplate).
    The solution is to wrap these operations with transactionTemplate execute method.
    The only flaw is that main method doesn't stop execution after all. I have to exit it manually.
    What can be the reason?



    Code:
    service.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
               http://www.springframework.org/schema/aop
                    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    
        <context:annotation-config/>
    
        <bean id="dataSourceJNDI"
              class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="org.postgresql.Driver"/>
            <property name="url" value="jdbc:postgresql://localhost:5432/springbase?autoReconnect=true"/>
            <property name="username" value="webmodule"/>
            <property name="password" value="1234"/>
        </bean>
    
        <bean id="dataSource"
              class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
            <property name="targetDataSource" ref="dataSourceJNDI"/>
            <property name="defaultAutoCommit" value="true"/>
            <property name="defaultTransactionIsolationName" value="TRANSACTION_SERIALIZABLE"/>
        </bean>
    
    
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
            <constructor-arg ref="dataSource"/>
        </bean>
    
        <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
            <constructor-arg ref="sessionFactory"/>
        </bean>
    
        <bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
    
        <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init"
              destroy-method="close">
            <!--  when close is called, should we force transactions to terminate or not? -->
            <property name="forceShutdown" value="true"/>
        </bean>
    
        <!-- Also use Atomikos UserTransactionImp, needed to configure Spring  -->
        <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
            <property name="transactionTimeout" value="300"/>
        </bean>
    
        <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
            <property name="transactionManager" ref="atomikosTransactionManager"/>
            <property name="userTransaction" ref="atomikosUserTransaction"/>
        </bean>
    
        <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
            <property name="transactionManager" ref="transactionManager"/>
        </bean>
    
        <bean id="sessionFactory"
              class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
            <!--<property name="configurationClass"
                      value="org.hibernate.cfg.Configuration"/>-->
            <property name="configLocation"
                      value="/org/coursera/hibernate.cfg.xml"/>
            <property name="hibernateProperties">
                <props>
                    <!--<prop
                            key="current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</prop>-->
                    <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
                    <!--<prop
                            key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>-->
                    <prop key="hibernate.show_sql">false</prop>
                    <prop key="hibernate.format_sql">true</prop>
                    <prop key="hibernate.connection.url">jdbc:postgresql://localhost:5432/springbase?autoReconnect=true
                    </prop>
                    <prop key="hibernate.connection.username">webmodule</prop>
                    <prop key="hibernate.connection.password">1234</prop>
                    <prop key="hibernate.c3p0.minPoolSize">5</prop>
                    <prop key="hibernate.c3p0.maxPoolSize">20</prop>
                    <prop key="hibernate.jdbc.batch_size">20</prop>
                    <prop key="hibernate.connection.autocommit">false</prop>
                    <prop key="hibernate.">false</prop>
                </props>
            </property>
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
    
        <bean id="connectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
            <!-- <property name="brokerURL" value="vm://localhost?broker.persistent=false"/>-->
            <property name="brokerURL" value="tcp://localhost:61616"/>
            <property name="redeliveryPolicy.maximumRedeliveries" value="-1"/>
            <property name="redeliveryPolicy.redeliveryDelay" value="5000"/>
            <property name="redeliveryPolicy.initialRedeliveryDelay" value="0"/>
        </bean>
    
        <bean id="XAConnectionFactory" class="com.atomikos.jms.AtomikosConnectionFactoryBean"
              init-method="init" destroy-method="close">
            <property name="uniqueResourceName" value="amq1"/>
            <property name="xaConnectionFactory" ref="connectionFactory"/>
        </bean>
        <bean id="logQueue" class="org.apache.activemq.command.ActiveMQQueue">
            <constructor-arg value="log.queue"/>
        </bean>
    
        <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
            <property name="connectionFactory" ref="XAConnectionFactory"/>
            <property name="receiveTimeout" value="10000"/>
            <property name="sessionTransacted" value="true"/>
        </bean>
    
    </beans>

    Code:
    public class MainHibernate {
        private static HibernateTemplate hibernateTemplate;
        private static TransactionTemplate txTemplate;
        private static JmsTemplate jmsTemplate;
        private static Queue queue;
    
        static {
            ApplicationContext context =
                    new ClassPathXmlApplicationContext(new String[]{"service.xml"});
    
            hibernateTemplate = context.getBean("hibernateTemplate", HibernateTemplate.class);
            txTemplate = context.getBean("transactionTemplate", TransactionTemplate.class);
            jmsTemplate = context.getBean("jmsTemplate", JmsTemplate.class);
            queue  = context.getBean("logQueue", Queue.class);
        }
    
        public static void main(String[] args) {
            txTemplate.execute(new TransactionCallback<Void>() {
                public Void doInTransaction(TransactionStatus txStatus) {
                    try {
                        send();
                        System.out.println("Has already sent");
                        save();
                    } catch (RuntimeException e) {
                        txStatus.setRollbackOnly();
                        throw e;
                    }
                    return null;
                }
            });
        }
    
        public static void send() {
            jmsTemplate.send(queue, new MessageCreator() {
                public Message createMessage(Session session) throws JMSException {
                    MapMessage target = session.createMapMessage();
                    target.setString("message", "hello");
                    return target;
                }
            });
        }
    
        public static void save() {
            Foo foo = new Foo("fuuu");
            hibernateTemplate.saveOrUpdate(foo);
            System.out.println(foo);
        }
    
    }

    Unless it works fine I would still like to know if it is the optimal way to manage distributed transactions. Is there any possibility to do the same without transactionTemplate?

    And one more thing. Imagine there is some service class. Some of it methods require distributed transactions and some do not. How can I on the method level vary the transactionManager?
Working...
X