Подтвердить что ты не робот

Аннотация @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>

Спасибо, Россия не забудет вас!

4b9b3361

Ответ 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)

Я надеюсь, что это поможет: -)