0

I have a requirement where the messages are put into the queue and then a method call is made to update the DB which is done through Hibernate. I want to make this as part of a single transaction, so that if the update call in the db fails the JMS roll back and do not put message in the queue. I tried configuring it but looks like i am missing something. Any help will be appreciated.

and method where i am calling JMS and DAO is

@Transactional(rollbackFor = Exception.class)               
public boolean retrieveBatchOrders(BatchPullCriteria batchPullCriteria) throws SQLException, IOException{

    List<IntrmStrg> IntrmStrgOrderLst  = iStorageDAO.retrieveByStoreId(batchPullCriteria);
    List<IntrmStrg> IntrmStrgFinalLst  = iStorageDAO.retrieveOrdersByStoreIdLst(batchPullCriteria,IntrmStrgOrderLst);
    sendMsgToQueue.sendMessageToTarget(IntrmStrgFinalLst);

    iStorageDAO.updateOrdersStatus(IntrmStrgFinalLst,batchPullCriteria.getRetrievedBy(),BATCHRTRVD);
    return true;
}

@Transactional

public void updateOrdersStatus(List<IntrmStrg> IntrmStrgLst , String retrivedBy, String status ){
        Date retriveDate = new Date();
        Timestamp retriveDTimestamp = new Timestamp(retriveDate.getTime());
    try{
        for (Iterator<IntrmStrg> iterator = IntrmStrgLst.iterator(); iterator.hasNext();) {
            IntrmStrg intrmStrg = (IntrmStrg) iterator.next();
            intrmStrg.setRtrvdBy(retrivedBy);
            intrmStrg.setRtrvdDt(retriveDTimestamp);
            intrmStrg.setStts(status);
            LOGGER.info("Updating Order Status with ID" + intrmStrg.getIntrmStrgId());
            getHibernateTemplate().getSessionFactory().getCurrentSession().beginTransaction();
            getHibernateTemplate().update(intrmStrg);
            LOGGER.info("Updated Order Status with ID" + intrmStrg.getIntrmStrgId());
            getHibernateTemplate().getSessionFactory().getCurrentSession().getTransaction().commit();
        }
    }
    catch(HibernateException he)
    {
        getHibernateTemplate().getSessionFactory().getCurrentSession().getTransaction().rollback();
    }


    if (LOGGER.isDebugEnabled()) {
        LOGGER.info("Order Status Updated");    
    }

}

application.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:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    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/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">


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


   <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">


   </bean>





    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="oracle.jdbc.OracleDriver" />
        <property name="url"
            value="" />
        <property name="username" value="" />
        <property name="password" value="" />
    </bean>


    <bean id="iStorageSessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource">
            <ref local="dataSource" />
        </property>
        <property name="mappingDirectoryLocations">
            <list>
                <value>classpath:org/entity</value>
            </list>

        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
                <prop key="hibernate.default_schema">DEV1</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>

    </bean>


    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
        lazy-init="true">
        <property name="dataSource" ref="dataSource" />
    </bean>

        <!-- -DAO Beans -->

    <bean id="storageDAO" class="org.kp.oppr.iStorage.dao.IStorageDAOImpl" >
    <property name="sessionFactory">
            <ref local="iStorageSessionFactory" />
        </property>
    </bean>

    <!--  Service Beans  -->
    <bean id="iStorageService" class="org.kp.oppr.iStorage.services.IStorageServiceImpl" >
    </bean>


        <!-- BROKER CONNECTION SETTING FOR TARXHB00 -->
    <bean id="jmsFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
        <property name="hostName" value="${mq.conn.hostName}" />
        <property name="port" value="${mq.conn.hostPort}" />
        <property name="queueManager" value="${mq.conn.queueManager}" />
        <property name="channel" value="${mq.conn.channel}" />
        <property name="transportType" value="${mq.conn.transportType}" />
    </bean>

    <bean id="jmsFactorySecurity"
        class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
        <property name="targetConnectionFactory" ref="jmsFactory" />
        <property name="username" value=" " />
        <property name="password" value=" " />
    </bean>

    <bean id="jmsQueueSender" class="org.kp.oppr.storage.jms.JmsQueueSender">
        <property name="connectionFactory" ref="jmsFactorySecurity"></property>
    </bean>


    <bean id="SendMsgToQueue" class="org.kp.oppr.storage.jms.SendMsgToQueue">
    <property name="queueNamePrfix" value="${QUEUE_PREFIX}"></property>
    <property name="queueNameSufix" value="${QUEUE_SUFFIX}"></property>
    </bean>

    <bean id="iStorageConfig" class="org.kp.oppr.storage.config.storageConfig">
        <property name="maxNumberofOrders" value="${MAX_ORDER_COUNT}"></property>
    </bean>




</beans>
Adrian Shum
  • 38,812
  • 10
  • 83
  • 131
Guest
  • 455
  • 10
  • 20
  • why don't you just put the message to the queue _after_ a successful db update? – muratgu Oct 31 '12 at 00:43
  • No, I have to put the message first, then go to db update the data, and if it is successful then commit the entire transaction. If there is DB failure then i need to roll the messages. – Guest Oct 31 '12 at 01:24

1 Answers1

0

The main problem is the transaction manager you are using is not XA awared.

What container are you deploying your application to? Spring provides Transaction Managers that works with main containers in the market.

If it is a standalone application, or it is running on containers that do not support JTA, you may want to use some other transaction manager in your app, like Bitronix or Atomikos

Adrian Shum
  • 38,812
  • 10
  • 83
  • 131
  • It is running in web sphere, the point is i dont have a complete understanding of the configuration which is needed to support that. – Guest Oct 31 '12 at 04:27
  • Leave only one transaction manager in Spring app context, and use org.springframework.transaction.jta.WebSphereUowTransactionManager as the class for the transaction manager. Go to have a Google with "hibernate spring websphere" and you should be able to find plenty of information on how to setup – Adrian Shum Oct 31 '12 at 07:18