컴퓨터활용/자바

Transaction rolled back because it has been marked as rollback-only

멜번초이 2012. 4. 25. 14:31


오픈을 앞둔 시점에 transaction 관리를 강화하기 위하여 transaction.xml 에 아래와 같은 AOP 를 추가하였다.  여기서 ${service.basePackage} 는 profile.properties 에 정의 되어 있다. 파일명이 Service로 끝나는 파일은 일괄 적용한다는 의미이다. 물론 이것의 구현체도 대상에 포함된다.


<aop:config>

<aop:advisor pointcut="execution(* ${service.basePackage}..*Service.*(..))" advice-ref="txAdvice" />

</aop:config>

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

<tx:attributes>

<tx:method name="*"/>

</tx:attributes>

</tx:advice>


그랬더니 org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only  오류가 발생되었다. 


UnexpectedRollbackException 이란 다른 프로그램에서 rollback 처리가 먼저 되었다는 뜻이므로 해당 프로그램에서 호출하는 모든 프로그램을 따라 가면서 끝까지 추적해야 개별 트랜젝션을 선언해서 사용하는 문제의 프로그램을 찾아낼 수 있다.


일부 프로그램에서는  업무 특성상 불가피하게 프로그램 속에서 transaction을 직접 생성하여 rollback, commit 을 직접 처리하고 있는 경우가 있는데 인터넷을 찾아 보니 이런 것들과 AOP로 선언한 것이 서로 충돌하니 하나만 정책적으로 선택해야 한다고 하였다.  결국 논의 끝에 프로그램속의 프로그램적 트랜젝션 선언을 모두 삭제하고 @Transactional을 일관적으로 사용하도록 하였다.  마찬가지로 @Transactional 어노테이션을 사용한 메소드에서 직접 트랜젝션을 생성하고 commit, rollback을 하게 되면 동일한 오류가 발생된다. 


AOP를 적용하였다 하더라도 프로그램에서 트랜젝션을 선언하여 사용할 경우 


우선 @Transactional 을 적용한 후 어느 정도 안정화 되면 제거했던 pointcut AOP를 다시 적용해 볼 것이다.


<참고 : http://open.egovframe.go.kr/projects/freediscussion/qna/423>

Spring에서의 transaction은 크게 2가지 방식이 있습니다. 
programmatic 방식과 declarative 방식입니다. 

context-transaction.xml 부분이 AOP를 사용하여 선언적으로 transaction을 처리하는 방식이고.. 
java 소스상에 트랜젝션을 생성하고 commit, rollback를 호출하는  것은 프로그램 방식입니다.. 

둘 중에 하나만 처리하시면 transaction이 처리되기 때문에 AOP를 사용할 경우 java 소스상에 기술된 transaction처리 로직은 필요치 않습니다.