본문 바로가기

IT/Java

@Transactional 이란? 사용이유

1. 스프링의 트랜잭션 지원

  - 스프링은 코드 기반의 트랜잭션 처리(Programmatic Transaction) 뿐만 아니라 선언적 트랜잭션(Declarative Transaction)을 지원하고 있다. 스프링이 제공하는 트랜잭션 템플릿 클래스를 이용하거나 설정 파일, 어노테이션을 이용해서 트랜잭션의 범위 및 규칙을 정의할 수 있다.

 

 

2. 선언적 트랜잭션 처리

  - 선언적 트랜잭션은 설정 파일이나 어노테이션을 이용해서 트랜잭션의 범위, 롤백 규칙 등을 정의

  - 다음과 같은 2가지 방식으로 정의

    1) <tx:advice> 태그를 이용한 트랜잭션 처리

    2) @Transactional 어노테이션을 이용한 트랜잭션 설정



다음 소스로 예를 들어보겠다.

     /**

     * 사업부 정보 등록,수정

     * @param map

     * @return

     * @throws Exception

     */

    @Transactional

    public int saveDivisionData(Map<String, Object> map) throws Exception {

      int cnt = companyDAO.saveDivisionData(map);

       

      // 사업부 수정이 정상적으로 처리되면 대상 사업부를 확산대상으로 지정한다.

      if(cnt == 1){

        companyDAO.saveExtensionTarget(map);

      }

      

        return cnt;

    }


@Transactional을 써주는 이유?

 companyDAO.saveDivisionData 에서 처리한 쿼리문이 정상적으로 완료가 되고, companyDAO.saveextensionTarget 에서 처리 도중 에러가 났을 때

 companyDAO.saveDivisionData 에서 처리한 쿼리를 자동 rollback 해주기 위해 사용된다.


만약 저 어노테이션을 써주지 않는다면, 위에꺼는 정상적으로 완료가 되었기 때문에 직접 save한 division 데이터를 복구 시켜놔야함...



- 인터페이스를 구현한 클래스로 선언된 빈은 인터페이스 메소드에 한해서 트랜잭션이 적용됨

- 인터페이스에 붙은 @Transactional 선언은 인터페이스 내의 모든 메소드에 적용됨

- 동시에 메소드 레벨에도 @Transactional을 지정할 수 있다. 메소드 선언 > 인터페이스 선언

- 클래스의 @Transactional > 인터페이스의 @Transactional

- @Transactional 적용 대상은 미리 결정하고 애플리케이션 안에서 통일하는게 좋음. 인터페이스와 클래스 양쪽에 불규칙하게 @Transactional이 혼용되는 건 바람직하지 못함




context-transaction.xml 파일에 아래와 같이 선언

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

      <property name="dataSource" ref="dataSource"/>

    </bean>

    

    <tx:advice id="txAdvice" transaction-manager="txManager">

        <tx:attributes>

            <tx:method name="select*" read-only="true" />

            <tx:method name="list*" read-only="true" />

            <tx:method name="retrieve*" read-only="true" />

            <tx:method name="get*" read-only="true" />

            <tx:method name="find*" read-only="true" />

            <tx:method name="view*" read-only="true" />

            <tx:method name="*Move" read-only="true" />

            <tx:method name="insert*" propagation="REQUIRED" />

            <tx:method name="update*" propagation="REQUIRED" />

            <tx:method name="delete*" propagation="REQUIRED"/>

            <tx:method name="save*" propagation="REQUIRED"/>

            <tx:method name="create*" propagation="REQUIRED"/>

            <tx:method name="merge*" propagation="REQUIRED"/>

            <tx:method name="execute*" propagation="REQUIRED"/>

            <tx:method name="excel*" propagation="REQUIRED"/>

            <tx:method name="CALL" propagation="REQUIRED"/>

            <tx:method name="*" rollback-for="Exception"/>

        </tx:attributes>

    </tx:advice>

    

    <aop:config>

        <aop:pointcut id="requiredTx" expression="execution(* com.????.??..impl.*Impl.*(..))"/>

        <aop:advisor advice-ref="txAdvice" pointcut-ref="requiredTx" />

    </aop:config>

    

    <tx:annotation-driven transaction-manager="txManager"/>    // @Transactional을 사용할 때 필요한 설정은 다음 한 줄 뿐이다. <tx:annotation-driven> 태그는 등록된 빈 중에서 @Transactional이 붙은 클래스나 인터페이스 또는 메소드를 찾아 트랜잭션 어드바이스를 적용해 준다. 






참고: http://snoopy81.tistory.com/335