Annotation @Transactional. How to rollback?

JavaHibernateSpring

Java Problem Overview


I used this annotation successfully for a Dao class. And rollback works for tests.

But now I need to rollback real code, not just tests. There are special annotations for use in tests. But which annotations are for non-test code? It is a big question for me. I spent a day for that already. The official documentation did not meet my needs.

class MyClass { // this does not make rollback! And record appears in DB.
    	EmployeeDaoInterface employeeDao;

    	public MyClass() {
        	ApplicationContext context = new ClassPathXmlApplicationContext(
	        		new String[] { "HibernateDaoBeans.xml" });
    		employeeDao = (IEmployeeDao) context.getBean("employeeDao");
         }

    	@Transactional(rollbackFor={Exception.class})
	public void doInsert( Employee newEmp ) throws Exception {
		employeeDao.insertEmployee(newEmp);
		throw new RuntimeException();
	}
}

employeeDao is

@Transactional
public class EmployeeDao implements IEmployeeDao {
	private SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	public void insertEmployee(Employee emp) {
		sessionFactory.getCurrentSession().save(emp);
	}
}

And here is a test for which the annotations work well:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/HibernateDaoBeans.xml" })
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)
@Transactional
public class EmployeeDaoTest {

	@Autowired
	EmployeeDaoInterface empDao;

	@Test
	public void insert_record() {
       ...
       assertTrue(empDao.insertEmployee(newEmp));
    }

HibernateDaoBeans.xml

   ...
<bean id="employeeDao" class="Hibernate.EmployeeDao">
	<property name="sessionFactory" ref="sessionFactory" />
</bean>
    <tx:annotation-driven transaction-manager="txManager"/>

<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
	<property name="sessionFactory" ref="sessionFactory" />
</bean>
   ...



**YES, I rolled back the transaction. I just added BEAN for the service... and then annotation @Transactional begin to work :-) **

<bean id="service" class="main.MyClass">
	<property name="employeeDao" ref="employeeDao" />
</bean>

Thanks all, Russia will not forget you!

Java Solutions


Solution 1 - Java

Just throw any RuntimeException from a method marked as @Transactional.

By default all RuntimeExceptions rollback transaction whereas checked exceptions don't. This is an EJB legacy. You can configure this by using rollbackFor() and noRollbackFor() annotation parameters:

@Transactional(rollbackFor=Exception.class)

This will rollback transaction after throwing any exception.

Solution 2 - Java

or programatically

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

Solution 3 - Java

You can throw an unchecked exception from the method which you wish to roll back. This will be detected by spring and your transaction will be marked as rollback only.

I'm assuming you're using Spring here. And I assume the annotations you refer to in your tests are the spring test based annotations.

> The recommended way to indicate to the Spring Framework's transaction infrastructure that a transaction's work is to be rolled back is to throw an Exception from code that is currently executing in the context of a transaction.

and note that:

> please note that the Spring Framework's transaction infrastructure code will, by default, only mark a transaction for rollback in the case of runtime, unchecked exceptions; that is, when the thrown exception is an instance or subclass of RuntimeException.

Solution 4 - Java

For me rollbackFor was not enough, so I had to put this and it works as expected:

@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)

I hope it helps :-)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMoscow BoyView Question on Stackoverflow
Solution 1 - JavaTomasz NurkiewiczView Answer on Stackoverflow
Solution 2 - JavaStefan K.View Answer on Stackoverflow
Solution 3 - JavaAlex BarnesView Answer on Stackoverflow
Solution 4 - JavaRoberto RodriguezView Answer on Stackoverflow