- Today
- Total
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 재능이의 돈버는 일기
- StresslessLife
- K_JIN2SM
- 소소한 일상
- My Life Style & Memory a Box
- Blog's generation
- 공감 스토리
- 취객의 프로그래밍 연구실
- Love Me
- Dream Archive
- 세상에 발자취를 남기다 by kongmingu
- hanglesoul
- 카마의 IT 초행길
- 느리게.
- 미친듯이 즐겨보자..
- Joo studio
- Gonna be insane
- 악 다 날아갔어!! 갇대밋! 왓더...
- xopowo05
- 맑은공기희망운동
- 엔지니어 독립운동
- 혁준 블로그
- Simple in Complex with Simple
- 무의식이 의식을 지배한다
드럼치는 프로그래머
[Spring] 스프링 트래잭션 롤백이 되지 않을 때 확인 사항 본문
간혹 스프링 트랜잭션을 적용하였는데 예외 발생 시 롤백이 되지 않을 때가 있다.
안되는 이유야 여러 가지가 있겠지만 난 그 중 한 가지 문제에 대해서 작성하려고 한다.
일단 테스트하는 스프링 애플리케이션 컨텍스트의 트랜잭션 AOP 설정은 다음과 같이 선언적 트랜잭션을 사용하였다.
service 패키지 하위에 있는 모든 클래스 중 insert*, delete*, update* 이름에 매칭되는 메소드에 트랜잭션 설정
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="find*" read-only="true" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="servicePublicMethod" expression="execution(public * com.incross.svc.component..service..*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="servicePublicMethod" />
</aop:config>
테스트 코드는 다음과 같다.
문제가 발생되는 원인에 대해서 보여주려고 실패 case에 대한 메소드를 생성하였다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/test-application-context.xml"})
@ActiveProfiles("dev")
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void 트랜잭션롤백테스트_실패case() throws Exception {
User user = new User();
user.setUserId("abc1111");
user.setPassword("1111");
user.setUserName("kyu");
User user1 = new User();
user1.setUserId("abc2222");
user1.setPassword("2222");
user1.setUserName("kyu");
userService.insertUser(user, user1);
}
}
서비스 클래스의 insertUser 메소드 내부 코드이다.
다음과 같이 insert를 두 번 한 후 FileNotFoundException을 강제 발생하였다.
public void insertUser(User user, User user1) throws FileNotFoundException {
userDAO.insertUser(user);
userDAO.insertUser(user1);
// checked Exception 강제로 발생
throw new FileNotFoundException();
}
위와 같이 코드를 작성한 후 테스트를 돌리면 어떻게 될까?
아마 두 번 실행된 insertUser 트랜잭션에 대해 정상적으로 롤백이 되어야 한다고 생각한다.
하지만 스프링 트랜잭션 AOP는 default 옵션으로 unchecked Exception인 RuntimeException에 대해서만 롤백을 해준다.
즉, <tx:method name="insert*" propagation="REQUIRED" /> 설정이 다음과 같이 rollback-for 옵션이 지정된 것 같다.
<tx:method name="insert*" propagation="REQUIRED" rollback-for="RuntimeException" />
결과적으로 insert* 메소드에서 RuntimeException 발생 시에만 자동 롤백을 해준다는 것이다.
만약 FileNotFoundException 발생 시에도 롤백을 지원하고 싶다면 rollback-for="Exception" 와 같이 설정하면 된다.
하지만 난 이 방법은 추천하고 싶지 않다.
checked Exception인 FileNotFoundException 발생 시 try catch 블록을 이용하여 RuntimeException 으로 포장하는 편이 더 깔끔한 코드를 유지할 수 있기 때문이다.
public void insertUser(User user, User user1) {
userDAO.insertUser(user);
userDAO.insertUser(user1);
try {
// checked Exception 강제로 발생
throw new FileNotFoundException();
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
위의 코드를 보면 throws FileNotFoundException이 사라졌다.
결국 insertUser 메소드를 호출하는 쪽에서 FileNotFoundException에 대한 예외 처리를 하지 않아도 되기 때문에 코드의 가독성이 좋아진다.
'★─Programing > ☆─WebProgram' 카테고리의 다른 글
[Spring] 스프링 시큐리티 csrf (크로스도메인) 설정방법 (0) | 2017.04.12 |
---|---|
[Spring] @ControllerAdvice를 이용한 익셉션 처리 (0) | 2017.04.12 |
[JavaScript] 브라우저를 기준으로 움직이는 퀵메뉴 (0) | 2017.04.04 |
[JavaScript] 현재 실행중이 URL정보 (0) | 2017.04.04 |
[JavaScript] 날짜 및 시간 설정, 경과 시간 계산, 비교 (0) | 2017.04.04 |