Results 1 to 9 of 9

Thread: Spring / Hibernate / Atomikos using two transactions instead of one so rollback fails

  1. #1

    Default Spring / Hibernate / Atomikos using two transactions instead of one so rollback fails

    I think I almost have 2 phase commit working now using Atomikos. I can see the problem in my tm.out log. The problem is that the two database writes I do to database A and database B are done using two different transactions. The problem looks like is:

    1) A transaction is opened for database A;
    2) A write is done to database A;
    3) Voting occurs and is successful;
    4) Transaction is committed;
    5) Transaction is terminated;

    6) A NEW transaction is opened for database B;
    7) A write is attempted to database B but fails;
    8) Voting occurs and returns as failed
    9) A rollback occurs on database B only;
    10) The transaction is terminated.

    I would be grateful if someone could tell me how to get it working using a single transaction so that I can do a rollback on database A if the write to database B fails.

    My spring-config is:

    Code:
    <bean id="dataSourceProsoc" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
    	<property name="uniqueResourceName"><value>XADBMSProsoc</value></property>
    	<property name="xaDataSourceClassName"><value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value></property>
    	<property name="xaProperties">
    	    <props>
    		<prop key="databaseName">prosoc</prop>
    		<prop key="serverName">localhost</prop>
    		<prop key="port">3306</prop>
    		<prop key="user">prosoc</prop>
    		<prop key="password">prosoc-</prop>
    		<prop key="url">jdbc:mysql://localhost:3306/prosoc</prop>
    	    </props>
    	</property>
    	<property name="minPoolSize"><value>1</value></property>
    </bean>
    
    <bean id="dataSourceProsocForum" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
    	<property name="uniqueResourceName"><value>XADBMSProsocForum</value></property>
    	<property name="xaDataSourceClassName"><value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value></property>
    	<property name="xaProperties">
    	    <props>
    		<prop key="databaseName">prosoc</prop>
    		<prop key="serverName">localhost</prop>
    		<prop key="port">3306</prop>
    		<prop key="user">prosoc</prop>
    		<prop key="password">prosoc-</prop>
    		<prop key="url">jdbc:mysql://localhost:3306/prosoc_forum</prop>
    	    </props>
    	</property>
    	<property name="minPoolSize"><value>1</value></property>
    </bean>
    
    <bean id="sessionFactoryProsoc" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    	<property name="useTransactionAwareDataSource" value="true"/>
    	<property name="dataSource"><ref bean="dataSourceProsoc"/></property>
    	<property name="mappingResources">
    	   <list>
    	       <value>uk/co/prodia/prosoc/user/User.hbm.xml</value>
    	   </list>
    	</property>
    	<property name="hibernateProperties">
    	   <props>
    	       <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    	       <prop key="hibernate.connection.isolation">3</prop>
    	       <prop key="hibernate.current_session_context_class">jta</prop>
    	       <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</prop>
    	       <prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop>
    	       <prop key="hibernate.connection.release_mode">on_close</prop>
    	       <prop key="hibernate.show_sql">true</prop>
    	   </props>
    	</property>
    </bean>
    
    <bean id="sessionFactoryProsocForum" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    	<property name="useTransactionAwareDataSource" value="true"/>
    	<property name="dataSource"><ref bean="dataSourceProsocForum"/></property>
    	<property name="mappingResources">
    	   <list>
    	       <value>uk/co/prodia/prosoc/forum/mvnforum/MVNForumMember.hbm.xml</value>
    	   </list>
    	</property>
    	<property name="hibernateProperties">
    	   <props>
    	       <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    	       <prop key="hibernate.connection.isolation">3</prop>
    	       <prop key="hibernate.current_session_context_class">jta</prop>
    	       <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</prop>
    	       <prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop>
    	       <prop key="hibernate.connection.release_mode">on_close</prop>
    	       <prop key="hibernate.show_sql">true</prop>
    	   </props>
    	</property>
    </bean>
    
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
    	<property name="forceShutdown"><value>true</value></property>
    	<property name="startupTransactionService" value="true"/>
    </bean>
    
    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
    	roperty name="transactionTimeout"><value>300</value></property>
    </bean>
    
    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    	<property name="transactionManager"><ref bean="atomikosTransactionManager"/></property>
    	<property name="userTransaction"><ref bean="atomikosUserTransaction"/></property>
    </bean>
    
    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
    	<property name="sessionFactory"><ref bean="sessionFactoryProsoc"/></property>
    </bean>
    
    <bean id="user" class="uk.co.prodia.prosoc.persistence.hibernate.DAOUserImpl">
    	<property name="sessionFactory" ref="sessionFactoryProsoc"/>
    </bean>
    
    <bean id="mvnForumMember" class="uk.co.prodia.prosoc.forum.mvnforum.persistance.hibernate.DAOMVNForumMemberImpl">
    	<property name="sessionFactory" ref="sessionFactoryProsocForum"/>
    </bean>
    and my jta.properties is:

    Code:
    com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
    com.atomikos.icatch.console_file_name = tm.out
    com.atomikos.icatch.log_base_name = tmlog
    com.atomikos.icatch.tm_unique_name = com.atomikos.spring.jdbc.tm
    com.atomikos.icatch.console_log_level = DEBUG 
    com.atomikos.icatch.output_dir = /mnt/storage/work/svn/prosoc/trunk/prosoc/web/WEB-INF/logs
    Thanks for any assistance anyone may be able to offer on this.

  2. #2

    Default Success but is there a better way?

    Having read the documentation for spring a bit more I saw a part that mentioned that the connection will close at the end of the method call. Originally my Java code was:

    Code:
    public class ActionUpdateEmail extends BaseActionSupport {
    
        public String execute() {
    
            // Call to database A
            IfaceDAOUser ifaceDAOUser = (IfaceDAOUser) Config.getSpringBean("prosocUser");
            ifaceDAOUser.updateUserEmail(getServletRequest() , email);
                    
            // Call to database B
            IfaceForumUser ifaceForumUser = (IfaceForumUser)      Config.getSpringBean("prosocForumUser");
            ifaceForumUser.updateUserEmail(prosocUser.getUsername() , email);
    
        }
    }
    If I move the call to database B into the method

    Code:
    ifaceDAOUser.updateUserEmail(getServletRequest() , email);
    then I get the rollback as I would like. Is it possible to leave my code as it was as that seems like a neater way of doing things or is the new way the standard way of getting XA transactions to work?

    I have tried to make the ActionUpdateEmail class (shown above) @Transactional and added an entry for it in the spring-beans file but that didn't work. I also have the sessionFactories set with:

    Code:
    <prop key="hibernate.connection.release_mode">on_close</prop>
    Thanks for any suggestions.

  3. #3

    Default Ackkk, not quite working

    Well, I thought I had it working but just to make sure I went back to using non-XA datasources and I find that I get exactly the same behavior. A failed write to database B and the update to database A does not get committed. Maybe someone can clarify my thinking:

    1) I am doing two updates to databases A+B;
    2) The updates are both called from within the same transactional method;
    3) The method will not commit unless they both work as hibernate will rollback database A when the write to database B fails

    With the way I have my code set up it doesn't seem to matter if I use XA or not.

    Questions
    -----------------------
    1) Is the advantage of using XA via Atomikos that the database will be left in a consistent state?
    2) Could anyone give me an example of how, without XA (Atomikos) datasources the DB could be left in an inconsistent state?
    3) Is the structure of my code wrong?

  4. #4
    Join Date
    Sep 2004
    Posts
    1,086

    Default

    If your ActionUpdateEmail class is not created by Spring, @Transactional is ignored.

  5. #5

    Default

    Thank you for the reply, I think you are right.

    I had pretty much decided to go with the solution I had found but then also found a struts2-spring-plugin which I was not previously using. My ActionUpdateEmail is a Struts2 action class and I am now getting:

    Code:
    Action class [springManagedProsocActionUpdateEmail] not found
    error and am not sure why. I have:

    1) Added the struts2-spring-plugin-2.0.11.1.jar to my lib folder;
    2) Added the following to my spring-config file:

    Code:
    <bean id="springManagedProsocActionUpdateEmail" class="uk.co.prodia.prosoc.struts2.action.ActionUpdateEmail">
            <property name="sessionFactory" ref="sessionFactoryProsocForum"/>
    </bean>
    3) Added the following to my struts.xml file:

    Code:
    <constant name="struts.objectFactory" value="org.apache.struts2.spring.StrutsSpringObjectFactory" />
    4) Modified the action class attribute to point to the id of the bean in the spring-config file so that it looks like the following:

    Code:
    <action name="update-email!*" class="springManagedProsocActionUpdateEmail" method="{1}">
        <results in here ... ...>
    </action>
    I am not sure what else to do as I have followed the guide given at:

    http://struts.apache.org/2.x/docs/spring-plugin.html

    but I am sure that you suggestion is correct.

  6. #6

    Default

    I have fixed the problem and now have 2PC working correctly. In case anyone find it useful here is the thread that describes what I did:

    http://www.nabble.com/Struts2-and-sp...d18814302.html

  7. #7
    Join Date
    May 2009
    Posts
    3

    Default

    Hi all,
    I'm also trying to use Atomikos+Spring+JDBC, using 2 phase commit.
    Does anyone know how to encrypt com.atomikos.jdbc.AtomikosDataSourceBean password, which define in xmls.

    Thanks,
    filexxia

  8. #8

    Default encryption

    Hi,

    Atomikos does not offer out-of-the-box encryption. Are there any industry standards or best practices for this?

    Best

  9. #9
    Join Date
    Apr 2013
    Posts
    4

    Default

    Hi,

    I have two different databases.
    1.Oracle
    2. HSQLDB

    I am inseting one row in each database, Second database insert fails. So I want to rollback the entire transaction and first database sould not be committed.

    But in my code first database insert is getting committed.

    Here is my spring configuration
    Code:
    <?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:tx="http://www.springframework.org/schema/tx"
    	xmlns:aop="http://www.springframework.org/schema/aop"
    	xmlns:oxm="http://www.springframework.org/schema/oxm"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans 
    	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    	http://www.springframework.org/schema/oxm 
    	http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd 
    	http://www.springframework.org/schema/aop 
    	http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
    	http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    
    	<aop:aspectj-autoproxy proxy-target-class="true" />
    	<bean id="oracleDataSource"
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
    		<property name="url"
    			value="jdbc:oracle:thin:@172.168.1.1:1521:xe" />
    		<property name="username" value="xxx" />
    		<property name="password" value="xxx" />
    	</bean>
    	<bean id="hsqldbDataSource"
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
    		<property name="url" value="jdbc:hsqldb:hsql://localhost/" />
    		<property name="username" value="sa" />
    		<property name="password" value="" />
    	</bean>
    	<bean id="testAspect" class="com.demo.aop.TestAspect"></bean>
    	<bean id="XATester" class="com.demo.xa.XATesterClass">
    		<property name="oracleDatasource" ref="oracleDataSource"></property>
    		<property name="hsqldbDatasource" ref="hsqldbDataSource"></property>
    		<property name="transactionManager" ref="transactionManager"></property>
    	</bean>
    	<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
    		init-method="init" destroy-method="close">
    		<property name="forceShutdown">
    			<value>true</value>
    		</property>
    	</bean>
    
    	<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
    	</bean>
    	<tx:annotation-driven transaction-manager="transactionManager" />
    
    	<bean id="transactionManager"
    		class="org.springframework.transaction.jta.JtaTransactionManager">
    		<property name="transactionManager">
    			<ref bean="atomikosTransactionManager" />
    		</property>
    		<property name="userTransaction">
    			<ref bean="atomikosUserTransaction" />
    		</property>
    	</bean>
    	
    	<bean id="caroline" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager"><ref bean="transactionManager" /></property>
        <property name="target"><ref bean="XATester"  /></property>
        <property name="transactionAttributes">
            <props>
                <prop key="*">PROPAGATION_REQUIRED, -Exception</prop>
            </props>
        </property>
    	</bean>
    	<aop:config proxy-target-class="true">
    		<aop:aspect ref="testAspect">
    			<aop:pointcut id="myCut" expression="execution(public * *(..))" />
    			<aop:around pointcut-ref="myCut" method="log" />
    		</aop:aspect>
    	</aop:config>
    
    </beans>

    This is how i am doing database insert.

    Code:
    /**
     * 
     */
    package com.demo.xa;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.sql.DataSource;
    
    import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
    import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.TransactionDefinition;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.transaction.support.DefaultTransactionDefinition;
    
    /**
     * @author dp.prabu
     * 
     */
    public class XATesterClass implements TesterInterface {
    	private DataSource oracleDatasource;
    	private DataSource hsqldbDatasource;
    	private PlatformTransactionManager transactionManager;
    	
    
    	/**
    	 * @return the oracleDatasource
    	 */
    	public DataSource getOracleDatasource() {
    		return oracleDatasource;
    	}
    
    	/**
    	 * @param oracleDatasource the oracleDatasource to set
    	 */
    	public void setOracleDatasource(DataSource oracleDatasource) {
    		this.oracleDatasource = oracleDatasource;
    	}
    
    	/**
    	 * @return the hsqldbDatasource
    	 */
    	public DataSource getHsqldbDatasource() {
    		return hsqldbDatasource;
    	}
    
    	/**
    	 * @param hsqldbDatasource the hsqldbDatasource to set
    	 */
    	public void setHsqldbDatasource(DataSource hsqldbDatasource) {
    		this.hsqldbDatasource = hsqldbDatasource;
    	}
    
    	
    	/**
    	 * @return the transactionManager
    	 */
    	public PlatformTransactionManager getTransactionManager() {
    		return transactionManager;
    	}
    
    	/**
    	 * @param transactionManager the transactionManager to set
    	 */
    	public void setTransactionManager(PlatformTransactionManager transactionManager) {
    		this.transactionManager = transactionManager;
    	}
    	public void testMethod() {
    		try {	
    				SimpleJdbcInsert insertRecordHsqldb = new SimpleJdbcInsert(hsqldbDatasource).withTableName("temp");
    				Map<String,Object> parametersHsqldb = new HashMap<String,Object>();
    				parametersHsqldb.put("code", "3");
    				parametersHsqldb.put("name", "Prabu");
    				insertRecordHsqldb.execute(parametersHsqldb);
    				SimpleJdbcInsert insertRecord = new SimpleJdbcInsert(oracleDatasource).withTableName("EMP");
    				Map<String,Object> parameters = new HashMap<String,Object>();
    				parameters.put("id", "46");
    				parameters.put("name", "Prabu");
    				insertRecord.execute(parameters);
    				SimpleJdbcTemplate template2 = new SimpleJdbcTemplate(this.oracleDatasource);
    				String sql1 = "SELECT * FROM EMP";
    				List<Map<String, Object>> rows1=template2.queryForList(sql1);
    				System.out.println(rows1.size());
    				SimpleJdbcTemplate template = new SimpleJdbcTemplate(this.hsqldbDatasource);
    				String sql = "SELECT * FROM TEMP";
    				List<Map<String, Object>> rows=template.queryForList(sql);
    				System.out.println(rows.size());
    		} catch (Exception e) {
    			System.out.println(e.getMessage());
    		}
    	}
    }


    Please advise. I don know what is wrong with this code.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •