I am learning JTA and I have two databases one from oracle and another one from mysql. I have noticed a weird behavior I hope someone can shed some light please, the code and spring config are shown below.
Please find use case below:
When two save operations (userRepository.save,tutorialsRepository.save) from different database are called from the method (checkDistributedTransactions) and a runtime exception is thrown at the end purposely of the method then both table operation rolls back which is as expected for JTA.
When a find method(findByActive) is added in between the two save methods and a runtime exception is thrown at the end, only the last save method(tutorialsRepository.save) rolls back and the first one does not roll back. The issue is that I would expect both save method to roll back or i am wrong?
Finally when the find method is added before the two save method and a runtime exception is thrown at the end then both save method roll back as expected.
Please find implementation class below:
@Component
public class UserServiceImp {
@Autowired
UserRepository userRepository;
UserTable user;
@Autowired
TutorialsRepository tutorialsRepository;
Tutor tutorials;
String name;
@Transactional()
public void checkDistributedTransactions() {
user = new UserTable();
user.setUsername("testFoo");
user.setFirstname("firstname");
user.setLastname("lastname");
user.setActive("Y");
userRepository.save(user);
List<UserTable> userTableList = userRepository.findByActive("Y");
System.out.println("userTableList " + userTableList.size());
tutorials = new Tutor();
tutorials.setTutorial_id("3");
tutorials.setTutorial_title("hrm");
tutorialsRepository.save(tutorials);
throw new EmptyStackException();
}
}
Please find app context below:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:transaction="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<context:component-scan base-package="org.example" />
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
id="catalogEntityManagerFactory">
<property name="jpaProperties">
<map>
<entry key="hibernate.transaction.jta.platform" value-ref="jtaPlatform" />
</map>
</property>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jtaDataSource">
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
<property name="username" value="hr" />
<property name="password" value="unknown" />
</bean>
</property>
<property name="packagesToScan" value="org.example.domain.catalog" />
</bean>
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
id="directoryEntityManagerFactory">
<property name="jpaProperties">
<map>
<entry key="hibernate.transaction.jta.platform" value-ref="jtaPlatform" />
</map>
</property>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jtaDataSource">
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/mysqlDb" />
<property name="username" value="root" />
<property name="password" value="unknown" />
</bean>
</property>
<property name="packagesToScan" value="org.example.domain.directory" />
</bean>
<jpa:repositories base-package="org.example.domain.directory"
entity-manager-factory-ref="directoryEntityManagerFactory" />
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
id="jpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
<property name="showSql" value="true" />
</bean>
<context:annotation-config />
<jpa:repositories base-package="org.example.domain.catalog"
entity-manager-factory-ref="catalogEntityManagerFactory" />
<transaction:annotation-driven />
<bean class="java.lang.String" id="jtaPlatform">
<constructor-arg value="com.atomikos.icatch.jta.hibernate4.AtomikosPlatform" />
</bean>
<bean class="org.springframework.transaction.jta.JtaTransactionManager"
id="transactionManager">
<property name="transactionManager">
<bean class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown" value="false" />
</bean>
</property>
<property name="userTransaction">
<bean class="com.atomikos.icatch.jta.J2eeUserTransaction">
<property name="transactionTimeout" value="300" />
</bean>
</property>
<property name="allowCustomIsolationLevels" value="true" />
</bean>
</beans>
The method to call the implementation class below:
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "springContext.xml" });
UserServiceImp userServiceImp = (UserServiceImp) context.getBean("userServiceImp");
userServiceImp.checkDistributedTransactions();
}
Any idea when the find operation is added in between the two save method then why only the last save method rolls back instead of both?
Thanks in advance