Аннотация @Transactional. Как откат?
Я успешно использовал эту аннотацию для класса Dao. И откат работает для тестов.
Но теперь мне нужно откат реального кода, а не только тестов.
Существуют специальные аннотации для использования в тестах. Но какие аннотации для не-тестового кода?
Это большой вопрос для меня. Я потратил на это уже целый день. Официальная документация не отвечала моим потребностям.
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
@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);
}
}
И вот тест, для которого аннотации работают хорошо:
@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>
...
** ДА, я отменил транзакцию. Я просто добавил BEAN для службы... а затем аннотация @Transactional начнет работать:-) **
<bean id="service" class="main.MyClass">
<property name="employeeDao" ref="employeeDao" />
</bean>
Спасибо, Россия не забудет вас!
Ответы
Ответ 1
Просто выделите RuntimeException
метод, помеченный как @Transactional
.
По умолчанию все транзакции отката RuntimeException
, тогда как проверенные исключения не выполняются. Это наследие EJB. Вы можете настроить это с помощью параметров аннотации rollbackFor()
и noRollbackFor()
:
@Transactional(rollbackFor=Exception.class)
Это будет откат транзакции после броска any.
Ответ 2
или программно
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
Ответ 3
Вы можете удалить исключенное исключение из метода, который вы хотите отменить. Это будет обнаружено spring, и ваша транзакция будет отмечена как откат только.
Я предполагаю, что вы используете spring здесь. И я предполагаю, что аннотации, на которые вы ссылаетесь в своих тестах, - это аннотации на основе spring.
Рекомендуемый способ указать инфраструктуру транзакций spring Framework, которая должна быть откатна, - это выбросить исключение из кода, который в настоящее время выполняется в контексте транзакции.
и обратите внимание, что:
обратите внимание, что код инфраструктуры транзакции spring Framework по умолчанию будет отмечать только транзакцию для отката в случае времени выполнения, неконтролируемых исключений; то есть, когда выбрано исключение является экземпляром или подклассом RuntimeException.
Ответ 4
Если вы хотите создать метод Rollback() в вашем API, возможно, есть способ. Создайте новый метод().
@Component
public class MyDBApiImpl implements MyDBApi{
@Autowired private DummyExceptionLauncher dummyExceptionLauncher;
@Override
@Transactional(propagation=Propagation.MANDATORY)
public void rollback(){
try{
dummyExceptionLauncher.throwException();
}catch(RuntimeException ex){
log.debug("Transaction deliberately aborted");
}
}
}
Где
@Component
public class DummyExceptionLauncherImpl implements DummyExceptionLauncher{
@Override
@Transactional(propagation=Propagation.MANDATORY)
public void throwException(){
throw new RuntimeException("Exception deliberated thrown to abort exception");
}
}
Остерегайтесь, что вам может понадобиться исключить исключения отката "Транзакция, отмеченная как rollbackOnly".
Ответ 5
Для меня rollbackFor не хватало, поэтому мне пришлось поместить это, и оно работает как ожидалось:
@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
Я надеюсь, что это поможет: -)