I have a doubt related to transactions within transactions. For background, I have a School entity object which has Set of Students entity object mapped to it. I am using Spring Data JPA which is taking care of all the crud operations. I have a SchoolManagementService class which has @Transactional(readonly=true) set at the class level and for all updating methods I am using @Transactional over them. In my SchoolManagementService class I have a method deleteStudents(List) which I have marked as @Transactional. In this method I am calling StudentsRepository.delete(studentId) again and again. I want to make sure if any delete fails then the transaction should rollback for that checked exception. I am trying to test this with my spring junit test case (I am not using default rollback=true or@rollback(true) because I want this to be rollbacked because of some runtime exception I encounter at the repository delete method.
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class})
@ContextConfiguration(locations = {"classpath:PPLRepository-context.xml"})
public class TestClass{
@Test
@Transactional
public void testDeleteStudents(){
StudentManagementService.delete(randomList)
}
with this testcase it is deleting all the records but the last one. Ideally it should rollback and none of of entries should be deleted.
Here is my sprin settings file with TransactionMangaer configs
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init"
destroy-method="close">
<property name="forceShutdown" value="true" />
<property name="startupTransactionService" value="true" />
<property name="transactionTimeout" value="1000" />
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp" />
<!-- Configure the Spring framework to use JTA transactions from Atomikos -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="userTransaction" ref="atomikosUserTransaction" />
<property name="transactionSynchronizationName" value="SYNCHRONIZATION_ON_ACTUAL_TRANSACTION" />
</bean>
<!-- EntityManager Factory that brings together the persistence unit, datasource, and JPA Vendor -->
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="PPL_GMR">
<property name="dataSource" ref="PPL_GMRDS"></property>
<property name="persistenceUnitName" value="PPL_GMR"/>
<property name="persistenceXmlLocation" value="classpath:META-INF/PPL-persistence.xml"/>
<property name="jpaVendorAdapter" ref="PPL_GMRJPAVendorAdapter"/>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.transaction.manager_lookup_class" value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup"/>
<entry key="hibernate.connection.release_mode" value="on_close"/>
<entry key="hibernate.default_schema" value="${PPL.schema}"/>
</map>
</property>
</bean>
Can someone suggest where my understanding of transactions is wrong? Whatever I have read from the APIs I got this impression that if some method is @Transactional at the service layer and if it calls several @Transactional methods of Spring Data JPA repositories then if I encounter any Runtime exception then all the transactions should be rolled back. I even tried to simple create a testcase method as below:
@Test
@Transactional
public void testDeleteStudents(){
StudentRepository.delete(1);
StudentRepository.delete(2);// 2 id is not present so I will get a runtime exception.
}
Inspite of keeping @Rollback(true/false) on this method, this method deletes id 1 Student from the database. I thought that @Transactional at this testcase method will create a new transaction here and all the transactional delete methods from the StudentRepository will run in same transaction. And no student data will be committed until and unless no runtime exception is thrown.
Please help me understand transactions better as I am new to this. i am using Spring Data JPA with Oracle database.
Thanks in advance.
I think that the default behaviour is (even thought you don't have it on the test class)
so it will perform rollback when your test ends. Therefore there is no synchronization of hibernate session with the database and no queries SQL are issued to the database.
You have two posibilities. Either specify
or inject entity manager into your test and call
This will force hibernate to send all queries to the database. Please note that this will solve your problem with deleting non existing entity, but it doesn't behave exactly like new transaction, e.g. when you have missing foreign key it doesn't throw anything (this is predictable.
You can use this for checking the contents of entity returned by em.find(class, id) and check you relational mapping without the need to commit the transaction.