@Transactional 주석. 롤백하는 방법?


91

이 주석을 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>

감사합니다. 러시아는 당신을 잊지 않을 것입니다!

답변:


163

으로 RuntimeException표시된 메소드에서 아무거나 던지십시오 @Transactional.

기본적으로 모든 RuntimeException롤백 트랜잭션이 있지만 확인 된 예외는 그렇지 않습니다. 이것은 EJB 레거시입니다. rollbackFor()noRollbackFor()주석 매개 변수 를 사용하여이를 구성 할 수 있습니다 .

@Transactional(rollbackFor=Exception.class)

이 던지는 후 트랜잭션을 롤백합니다 모든 예외를.


1
나는 그것을 시도했다. 작동하지 않습니다! 나는 Dao 개체에서 직접 롤백 작업에 대해 말했는데, 작동 할 수 있습니다. @Transactional을 사용하는 Dao 메서드의 호출 순서를 사용하는 다른 개체에 대해 설명합니다. 그리고 저는 이것을 Dao라고 부르는 제 수업에 동일한 주석을 추가하려고합니다. 그러나 여기서는 작동하지 않습니다.
Moscow Boy

5
정말 이런 식으로 작동합니다 :-). 여러 DAO를 호출하는 서비스가있는 경우 서비스 @Transactional에도 주석 이 있어야합니다 . 그렇지 않으면 서비스에서 예외를 발생시키기 전에 각 DAO 호출이 시작되고 새 트랜잭션을 커밋합니다. 결론은 다음과 같습니다. 예외는로 표시된 메서드를 떠나야합니다 (이스케이프) @Transactional.
Tomasz Nurkiewicz

첫 번째 게시물에서 추가 된 코드를보십시오. 내가 가지고있는 코드의 일부가 있습니다. 그리고 실행 후 DB에 기록이 있습니다. => 롤백은 아직 작동하지 않습니다.
Moscow Boy

DAO에서 예외를 던지면 트랜잭션도 롤백되지 않습니까? 당신은 한 마십시오 org.springframework.orm.hibernate3.HibernateTransactionManager당신의 Spring 컨텍스트 구성? org.springframework.transaction로거 를 활성화하면 흥미로운 내용이 표시됩니까?
Tomasz Nurkiewicz

1
Spring Boot를 사용하고 DataSource를 자동 구성하도록두면 기본적으로 auto-commit이 true로 설정된 HikariDataSource를 사용합니다. false로 설정해야합니다. hikariDataSource.setAutoCommit (false); DataSourceTransactionManager 빈을 구성 할 때 @Configuration 클래스에서 이렇게 변경했습니다.
Alex

83

또는 프로그래밍 방식으로

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

12
예. 때로는 오류없이 롤백해야하기 때문입니다.
Erica Kane

2
당신은 생명의 은인입니다.
Walls

이것은 롤백 imo를 호출하는 더 적절한 방법입니다. 이상적으로는 알려진 또는 제어 된 조건에 대해 예외를 발생시키지 않으려 고합니다.
jalpino

2
때로는 작동하지 않습니다. 예를 들어, 제 경우에는 트랜잭션 서비스와 비 트랜잭션 저장소가 있습니다. 서비스에서 리포지토리를 호출하므로 서비스에서 오픈 한 트랜잭션에 참여해야합니다. 그러나 트랜잭션이 아닌 저장소에서 코드를 호출하면 트랜잭션이 존재한다는 사실에도 불구하고 NoTransactionException이 발생합니다.
Victor Dombrovsky

3
"비 트랜잭션 저장소"에서 어떤 트랜잭션을 롤백 하시겠습니까?
Stefan K.

5

롤백하려는 메서드에서 확인되지 않은 예외를 throw 할 수 있습니다. 이것은 봄에 감지되며 귀하의 거래는 롤백으로 만 표시됩니다.

여기서 Spring을 사용하고 있다고 가정합니다. 그리고 테스트에서 참조하는 주석이 스프링 테스트 기반 주석이라고 가정합니다.

트랜잭션의 작업이 롤백 될 것임을 Spring Framework의 트랜잭션 인프라에 표시하는 권장 방법은 트랜잭션 컨텍스트에서 현재 실행중인 코드에서 예외를 발생시키는 것입니다.

다음 사항에 유의하십시오.

Spring Framework의 트랜잭션 인프라 코드는 기본적으로 런타임, 확인되지 않은 예외의 경우에만 트랜잭션을 롤백하도록 표시합니다. 즉, throw 된 예외가 RuntimeException의 인스턴스 또는 하위 클래스 인 경우입니다.


1

나를 위해 rollbackFor는 충분하지 않았으므로 이것을 넣어야했고 예상대로 작동합니다.

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

나는 그것이 도움이되기를 바랍니다 :-)


1
더는 전혀 도움이되지 않습니다 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();당신 아래는 도움이
Enerccio
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.