Exception과 Transaction
Exception 과 Error
Exception 과 Error 는 한 마디로 개발자가 대응할 수 있냐 없냐로 구분할 수 있다.
- Exception : 프로그램을 실행 중 발생하는 예외 상황을 나타낸다. 예외는 프로그램이 실행되는 동안 발생할 수 있는 일반적인 에러를 포함한다. 예를 들어, 파일을 찾을 수 없는 경우, 네트워크 연결이 끊어진 경우, 잘못된 사용자 입력 등이 있다.
- Error : 프로그램이 더 이상 수행될 수 없는 심각한 예외 상황을 나타낸다. 일반적으로 Error는 시스템 수준의 문제를 나타내며, 프로그래머가 직접적으로 처리하기 어렵거나 불가능한 상황이다. 프로그램이 더 이상 복구할 수 없는 상황에서 발생하는데, 가장 흔한 예로는 OutOfMemoryError 가 있다.
자바에서는 이러한 예외를 처리하기 위해 'try', 'catch', 'finally', 'thorw', 'thorws' 등의 예외 처리 구문을 제공한다.
try {
// 예외가 발생할 수 있는 코드 작성
} catch {
// 예외를 처리하는 코드 작성
} finally {
// 항상 실행되는 코드 작성 (예외 발생 여부에 상관없이)
}
추가로 이러한 오류가 발생하는 시점에 따라 분류를 할 수도 있는데
1. 컴파일 에러 (compile-time error): 컴파일시에 발생하는 에러
2. 런타임 에러 (runtime error): 프로그램 실행시에 발생하는 에러
3. 논리적 에러 (logical error): 실행은 되지만 의도와 다르게 동작하는 것
로 나뉜다.
* 논리 에러 (logical error) 는 버그라고 생각하면 된다. 프로그램이 실행되고 작동하는데는 아무런 문제가 없는 오류지만, 결과가 예상과 달라 개발자가 의도한 작업을 수행하지 못하게 되어 서비스 이용에 지장이 생길 수 있다.
이러한 논리 에러는 프로그램이 멀쩡하게 돌아가기 떄문에 따로 에러 메시지는 발생하지 않는다. 따라서 논리 에러를 피하기 위해서는 프로그램의 전반적인 코드와 알고리즘을 체크하고 테스트를 진행해야 한다.
* 컴파일 에러 (compile-time error) : 컴파일 에러는 컴파일 단계에서 오류를 발견하면 컴파일러가 에러 메시지를 출력해주는 것을 말한다. 대표적인 컴파일 에러 발생의 원인은 '문법 구문 오류 (syntax error)'를 들 수 있다.
* 런타임 에러 (runtime error) : 프로그램 실행 중에 에러가 발생하여 잘못된 결과를 얻는 경우 런타임 에러가 발생할 수 있다.
자바의 오류 클래스 계층 구조를 확인해보자
자바에서 다루는 모든 예외 처리는 Exception 클래스에서 처리한다. Exception 클래스는 RunTimeException 과 CompileException 으로 구분 할 수 있다.
그렇다면 RuntimeException 클래스의 종류에는 어떠한 것들이 있을까?
@Transaction 어노테이션
@Transaction 어노테이션은 saveDataInTransaction 메서드에 적용되어있다. 이 메서드가 실행될때 스프링은 트랜잭션을 시작하고, 메서드가 완료되면 트랜잭션을 커밋한다. 만약 메서드 수행 중 예외가 발생하면 트랜잭션은 롤백된다.
Spring @Transactional 선언 시 기본 속성은 아래와 같다.
@Transactional
//@Transactional(rollbackFro = {RuntimeException.class, Error.class}) 기본 속성
public void doSave(User userInfo) {
userInfoSaveDao.save(user);
}
RuntimeException 과 Error 가 발생했을 경우 기본적으로 rollback이 된다. 해당 2가지 경우가 아니면 rollback 되지 않는다. (컴파일 예외는 rollback되지 않는다)
하지만 트랜잭션을 rollback 하는 다른 방법들이 존재한다.
1. @Transactional 의 옵션 값을 변경
@Transactional(rollbackFor = {Exception.class})
public void doSave(User userInfo) {
userInfoSaveDao.save(user);
}
위와 같이 변경하면 모든 예외에 대해서 rollback을 진행하게 된다.
2. RuntimeException
@Transactional(rollbackFor = {RuntimeException.class, Error.class})
public void doSave(User userInfo) {
userInfoSaveDao.save(user);
}
3. 수동으로 하는 rollback
@Autowired
private DataSourceTransactionManager txm;
@Transactional(rollbackFor = {Exception.class})
public void doSave(User userInfo) {
TransactionStatus tx = CommonUtils.getTransactionStatus(txm);
try {
userInfoSaveDao.save(user);
} catch(Exception e) {
tx.rollback();
}
}