💨 1. Java에서 예외 처리방법
자바에서 예외 처리는 프로그램의 오류를 안전하게 처리하고 앱의 안정성을 유지하는 중요한 개념입니다. 예외는 예상치 못한 상황에서 발생할 수 있는 오류들을 지칭하는데, 자바에서는 try-catch-finally
구문, throws
키워드, 그리고 커스텀 예외를 통해 다양한 예외 상황을 처리할 수 있습니다.
이 포스트에서는 자바에서 예외를 처리하는 방법을 세부적으로 설명하고, 예외 처리와 트랜잭션 처리의 관계를 알아본 뒤, 커스텀 예외를 만드는 방법까지 상세히 설명하겠습니다.
🙆♂️ 2. 자바에서 예외 처리하는 주요 방법
2.1 try-catch
구문 사용하기
try-catch
구문은 자바에서 예외를 잡아내고 처리하는 가장 기본적인 방법입니다.
- try: 예외가 발생할 가능성이 있는 코드를 감싸는 블록입니다.
- catch: 특정 예외가 발생했을 때 실행되는 블록으로, 예외 종류에 따라 여러 개를 작성할 수 있습니다.
- finally: 예외 발생 여부와 관계없이 항상 실행되는 블록으로, 주로 자원을 해제할 때 사용합니다.
try {
// 예외가 발생할 가능성이 있는 코드
} catch (ExceptionType e) {
// 예외 처리 코드
} finally {
// 예외 발생 여부와 상관없이 실행되는 코드
}
2.2 throws
키워드 사용하기
메소드에서 특정 예외를 처리하지 않고 호출한 쪽에 넘길 때 사용합니다. 이를 예외 전가라고 하며, 메소드 선언부에 throws
키워드를 붙여 선언합니다.
public void exampleMethod() throws IOException {
// 예외 발생 가능성이 있는 코드
}
이 방식은 호출자가 예외를 직접 처리하도록 책임을 넘기기 때문에 예외가 발생한 상황에서 유연하게 대응할 수 있습니다.
🤲 3. 트랜잭션과 예외 처리의 관계
트랜잭션은 데이터베이스에서 하나의 작업 단위로, 모든 작업이 성공적으로 완료되거나, 하나라도 실패하면 전체를 롤백하는 특징이 있습니다. Java와 스프링에서는 @Transactional
애너테이션을 통해 트랜잭션을 관리하는데, 예외가 발생하면 트랜잭션은 자동으로 롤백됩니다.
그러나, 예외가 발생한다고 무조건 롤백이 되지는 않습니다. 예외 유형에 따라 트랜잭션의 동작이 달라지기 때문인데
3.1 기본적인 트랜잭션 롤백 규칙
- Unchecked Exception (런타임 예외):
RuntimeException
과 그 하위 예외들은 기본적으로 트랜잭션을 롤백합니다. - Checked Exception:
Exception
을 상속한 예외는 트랜잭션을 롤백하지 않으며, 필요 시 직접 설정이 필요합니다.
스프링에서는 이러한 규칙을 이해하고 @Transactional 애너테이션의 rollbackFor
속성을 사용해 롤백할 예외 유형을 지정할 수 있습니다.
@Transactional(rollbackFor = Exception.class)
public void someMethod() throws Exception {
// 트랜잭션 관리 코드
}
🙅♂️ 4. try-catch를 사용할 때 트랜잭션이 롤백되지 않는 이유
스프링의 트랜잭션 처리는 프록시(Proxy) 패턴을 통해 이루어집니다. @Transactional
이 적용된 메소드에서 예외가 발생하면 프록시는 해당 예외를 감지해 트랜잭션을 롤백하게 됩니다. 하지만 try-catch
구문으로 예외를 잡아내면, 스프링은 예외가 발생했는지 인지하지 못하고 트랜잭션을 정상 종료(커밋) 시키게 됩니다.
예시 코드
@Transactional
public void processTransaction() {
try {
// 예외가 발생할 수 있는 코드
} catch (Exception e) {
// 예외를 잡아버려서 트랜잭션 롤백이 되지 않음
System.out.println("Exception caught: " + e.getMessage());
}
}
이 코드에서는 예외가 발생하더라도 catch
에서 처리해버리면 트랜잭션이 자동으로 롤백되지 않습니다. 이를 해결하기 위해 catch
블록에서 RuntimeException
으로 다시 예외를 던지거나 throws
를 사용해 상위 메소드로 예외를 전파할 수 있습니다.
@Transactional
public void processTransaction() {
try {
// 예외가 발생할 수 있는 코드
} catch (Exception e) {
System.out.println("Exception caught: " + e.getMessage());
throw new RuntimeException(e); // 예외를 다시 던져 트랜잭션 롤백 유도
}
}
🌌 5. 커스텀 예외 만들기와 글로벌 예외 처리
자바에서는 사용자 정의 예외(커스텀 예외)를 만들어 특정 상황에서 발생하는 예외를 명확하게 구분할 수 있습니다. 커스텀 예외는 Exception 클래스를 상속하거나, 더 넓은 범위에서 잡기 위해 RuntimeException을 상속받아 만들 수 있습니다.
5.1 커스텀 예외 만들기 예시
public class CustomException extends RuntimeException {
public CustomException(String message) {
super(message);
}
}
이렇게 만든 커스텀 예외는 필요할 때마다 throw
로 발생시킬 수 있으며, 예외 메시지나 추가 정보를 전달해 디버깅에 도움이 됩니다.
public void riskyMethod() {
if (/* 특정 조건 */) {
throw new CustomException("커스텀 예외 발생: 특정 조건을 만족하지 않음");
}
}
5.2 커스텀 예외와 글로벌 예외 처리
스프링에서는 @ControllerAdvice
와 @ExceptionHandler
를 통해 글로벌 예외 처리를 할 수 있어요. 글로벌 예외 처리를 사용하면 특정 예외가 발생했을 때 일관된 응답을 반환할 수 있고, 모든 컨트롤러에 공통적으로 적용됩니다.
예시 코드
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(CustomException.class)
public ResponseEntity<String> handleCustomException(CustomException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleGeneralException(Exception ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
이 GlobalExceptionHandler
클래스는 커스텀 예외인 CustomException
이 발생하면 일관된 메시지와 상태 코드를 클라이언트에 반환하는 역할을 합니다. 이런 글로벌 예외 처리 덕분에 코드의 일관성을 유지하고 중복된 예외 처리 코드를 줄일 수 있습니다.
5.3 커스텀 예외와 트랜잭션 롤백 설정
커스텀 예외가 발생했을 때 트랜잭션이 롤백되길 원한다면, 커스텀 예외를 RuntimeException으로 상속하면 기본적으로 롤백됩니다. 만약 그렇지 않다면, @Transactional
애너테이션의 rollbackFor
속성을 설정해 강제로 롤백할 수 있습니다.
@Transactional(rollbackFor = CustomException.class)
public void someTransactionalMethod() throws CustomException {
throw new CustomException("커스텀 예외 발생으로 인한 롤백");
}
🛫 6. 예외 처리 흐름 요약
자바에서 예외가 발생했을 때의 처리를 단계별로 보면 다음과 같습니다.
- 예외 발생: 예외가 발생하면 JVM은 이를 인식하고 예외 객체를 생성합니다.
- 예외 처리 탐색: JVM은
try-catch
블록을 찾고, 일치하는catch
블록이 있는지 확인합니다. - 예외 처리 수행: 해당 예외와 일치하는
catch
블록이 있으면, 그 안의 코드가 실행되고 예외는 처리됩니다. - finally 블록 실행:
finally
블록이 있으면 무조건 실행됩니다. - 트랜잭션 롤백 여부 판단: 예외가
RuntimeException
또는Error
이면 기본적으로 트랜잭션이 롤백됩니다. 그렇지 않으면 설정에 따라 다르게 동작합니다.
요약
자바의 예외 처리는 주로try-catch
,throws
, 그리고 커스텀 예외를 통해 관리합니다. 트랜잭션은RuntimeException
에 의해 롤백되며, 커스텀 예외의 경우도 상속된 클래스에 따라 롤백 여부가 결정됩니다. 또한, 글로벌 예외 처리를 통해 일관된 예외 응답을 반환하고 코드 중복을 줄일 수 있습니다.
'Java' 카테고리의 다른 글
[JAVA] Java로 Excel 파일 생성 및 관리: Apache POI 사용법 (0) | 2024.11.26 |
---|---|
[JAVA] Java의 예외 계층 구조와 개념 (4) | 2024.11.15 |
[JAVA] 프로젝트에서 PMD를 이용한 소스 품질 검사 (0) | 2024.11.11 |
[JAVA] Spring 돌아보기 Part.3 #JDBC #MyBatis #Multiple DataSources (4) | 2024.10.10 |
[JAVA] Spring Boot Redis 캐시 사용법 (0) | 2024.09.20 |