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!
Just throw any RuntimeException
from a method marked as @Transactional
.
By default all RuntimeException
s 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.
or programatically
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
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.
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 :-)
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
below you helped
Success story sharing
@Transactional
annotation as well. Otherwise each DAO call start and commits new transaction before you throw an exception in the service. The bottom line is: the exception must leave (escape) a method marked as@Transactional
.org.springframework.orm.hibernate3.HibernateTransactionManager
configured in your Spring context? If you enableorg.springframework.transaction
logger, does it show anything interesting?