ysk(0soo)
Lifealong
ysk(0soo)
전체 방문자
오늘
어제
  • 분류 전체보기 (238)
    • Java (50)
      • whiteship-java-study (11)
      • Java (28)
      • time (6)
    • Spring (68)
      • JPA (15)
      • Spring (1)
      • SpringBoot (1)
      • SpringMVC (6)
      • Spring Security (22)
      • Jdbc (1)
      • RestDocs (14)
      • log (6)
    • Kotlin (3)
    • Web (2)
      • nginx (1)
    • Database (14)
      • MySQL (5)
      • PostgreSQL (1)
      • SQL (1)
      • Redis (4)
    • C, C++ (0)
    • Git (1)
    • Docker (2)
    • Cloud (3)
      • AWS (3)
    • 도서, 강의 (0)
      • t5 (0)
    • 기타 (7)
      • 프로그래밍 (1)
    • 끄적끄적 (0)
    • CS (14)
      • 운영체제(OS) (2)
      • 자료구조(Data Structure) (9)
    • 하루한개 (12)
      • 우아한 테크코스-10분테코톡 (12)
    • 스터디 (12)
      • 클린 아키텍처- 로버트마틴 (2)
      • JPA 프로그래밍 스터디 (10)
    • 테스트 (34)
      • JUnit (19)
      • nGrinder (2)
      • JMeter (0)
    • Infra (3)
    • 프로그래머스 백엔드 데브코스 3기 (0)
    • 디자인 패턴 (3)
    • Issue (4)
    • system (1)
      • grafana (0)
      • Prometheus (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • github

공지사항

인기 글

태그

  • StructuredConcorrency
  • LocalDateTime
  • restdocs enum
  • AccessDecisionVoter 커스텀
  • node exporter basic auth
  • 동시성 제어
  • DataJpaTest
  • querydsl
  • 정규표현식
  • 가상 스레드
  • nGrinder
  • 인가(Authorization) 처리
  • 동일성
  • 가상 스레드 예외 핸들링
  • java
  • restdocs custom
  • jpa
  • tree
  • 동등성
  • 구조화된 동시성
  • AccessDecisionManager
  • scope value
  • 트랜잭션
  • AuthenticationException
  • nginx basic auth
  • FilterSecurityInterceptor
  • mysql
  • junit5
  • UserDetailsService
  • VirtualThread Springboot

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
ysk(0soo)

Lifealong

Java

에러와 예외 (Error, Exception)

2022. 11. 26. 19:29

오류(error) : 시스템에 무엇인가 비정상적인 상황이 발생한 경우. 프로그램이 실행 중 어떤 원인에 의해서 오작동을 하거나 비정상적으로 종료되는 경우가 있는데 이러한 결과를 초래하는 원인.

  • Java에서는 주로 JVM(Java Virtual Machine)에서 발생시키는 것이고, 예외(Exception)와 반대로 Application Code에서 잡아도 처리할 제대로 방법이 없다.
  • OutOfMemoryError, ThreadDeath, StackOverflowError 등

에러는 발생 시점에 따라서 3가지로 분류할 수 있다.

  • Compile Error (컴파일 에러) : 컴파일 할 때 발생하는 에러. syntax error(문법 오류)도 포함됨. - 컴파일 시 발생하는 에러
    • 소스코드를 컴파일을 하면 컴파일러가 소스코드에 대해 오타나 Syntax Error(잘못된 구문), 자료형 체크등의 기본적인 검사를 수행하여 오류를 잡아낼 수 있다.
    • 소스코드를 컴파일러가 컴파일하는 시점에서 발생하는 에러를 컴파일 에러라 하며 이 시점에서 발생하는 문제들을 수정 후 컴파일을 성공적으로 마칠경우 클래스 파일(*.class) 파일이 생성된다.
  • Runtime Error (런타임 에러) : 프로그램 실행 도중에 발생하는 에러 - 실행 시 발생하는 에러
    • 컴파일러는 컴파일 시점에서 문법 오류나 오타같은 컴파일 시점에서 예측 가능한오류는 잡아줄 수 있지만, 실행중 발생할 수 있는 잠재적인 에러까지는 잡을 순 없다.
    • 컴파일은 완료되어서 컴파일 에러는 없지만 실행 중 발생할 수 있는 에러이다.
  • Logical Error (논리적 에러) : : 컴파일도 잘되고 실행도 잘되지만 의도한 것과 다르게 동작하는 것.
    • 컴파일도 정상적으로 되고 런타임 에러도 발생하지 않았지만 개발자가 의도한 대로 동작하지 않는 에러를 말한다.
    • API가 응답값을 주도록 했으나 응답값을 안주거나, 아무 동작을 안하거나, 버그가 생기는 등을 의미한다

예외(exception) : 입력 값에 대한 처리가 불가능하거나, 프로그램 실행 중에 참조된 값이 잘못된 경우 등 정상적인 프로그램의 흐름을 어긋나는 것

  • Java에서 Exception은 개발자가 직접 Application Code내에서 처리 할 수 있어, 예외 상황에 대해 미리 예측하여 Handling할 수 있다.
  • Exception, RuntimException, IOException 등

오류가 시스템 레벨에서 발생한다면 예외(Expceiton)은 개발자가 구현한 로직에서 발생한다.

 

런타임 시점에서 발생하는 오류는 에러(error)와 예외(exception)으로 나뉜다.

컴파일러가 소스코드 컴파일중 발생한 에러를 잡았다 해서 실행 도중에 발생할 수 있는 잠재적인 오류까지는 검사할 수 없다 . 이것이 런타임 에러이다.

런타임 에러를 방지하기 위해서는 프로그램 실행 도중 발생할 수 있는 모든 경우의수를 고려하여 이에 대한 대비를 하는것이 필요한데

자바에서는 실행 시(rumtime) 발생할 수 있는 프로그램 오류를 에러(rror)와 예외(exception) 두가지로 구분하였다

따라서 개발자는 예외 처리(exception handling)를 통해 예외 상황을 처리할 수 있도록 코드의 흐름을 바꿀 필요가 있다.

• 에러(Error): 메모리 부족(OutOfMemoryError)이나 스택오버플로우(StackOverflowError)와 같이 일단 발생하면 복구할 수 없는 심각한 오류

• 예외(exception): 인자값 Null 에러, NPE(NullPointException)같은 발생하더라도 수습이 가능한 덜 심각한 오류.

 

자바 예외 클래스의 구조

자바는 실행 시 발생할 수 있는 오류들(Error와 Exception)을 클래스로 정의하였다.

  • 예외 클래스도 클래스이고, 모든 클래스의 조상은 Object 클래스이므로 Exception과 Error 클래스 역시 Object 클래스의 Object 클래스의 자손들이다.

예외 클래스들은 2그룹으로 나눌 수 있다.

  1. Exception 클래스를 상속받고 RuntimeException을 상속받지 않은 예외들 - CheckedException (확인된 예외)
  2. RuntimeException을 상속받은 예외들 - UncheckedException(확인되지 않은 예외)
  • Throwable : Java의 모든 오류 및 예외의 상위 클래스. 이 클래스(또는 해당 하위 클래스 중 하나)의 인스턴스인 개체만 JVM에 의해 throw되거나 Java throw문에 의해 throw될 수 있다.
    • 마찬가지로 이 클래스 또는 해당 하위 클래스 중 하나만 catch절로 catch할 수 있다.
    • 예외의 컴파일 타임 검사 목적을 위해, Throwable하위 클래스 도 Throwable아닌 하위 클래스는 확인된 예외로 간주한다. RuntimeExceptionError
  • Exception : 클래스 Exception과 해당 서브클래스는 애플리케이션이 파악하고자 하는 예외 조건을 보여주는 Throwable 이다.
    • 예외 클래스 및 RuntimeException을 상속받은 하위 클래스가 아닌 , 모든 하위 클래스 예외는 checked 예외이다.
      • RuntimeException은 Unchecked 예외이다.
    • 체크된 예외는 메서드 또는 구성 요소의 실행에 의해 슬로우며 메서드 또는 구성 요소의 경계 밖으로 전파될 수 있는 경우 메서드 또는 구성 요소의 throw 구로 선언해야 한다.
  • Error : 클래스 Error 는 애플리케이션이 catch 하는것을 시도해서는 안되며, 심각한 문제를 나타내는 Throwable의 하위 클래스.
    • 이러한 오류는 대부분 비정상적인 상태이다.
    • ThreadDeath 오류는 "정상적인" 조건이지만 대부분의 응용 프로그램이 오류를 catch하려고 시도해서는 안 되기 때문에 Error의 하위 클래스이다.
    • 메소드 실행 중에 발생할 수 있지만 포착되지 않은 Error의 하위 클래스를 throws 절에서 선언할 필요는 없다.
    • 즉, Error 와 Error의 하위 클래스는 컴파일 타임 예외 검사를 위해 unchecked 예외로 간주된다.

 

RuntimeException

RumtimeException은 JVM 정상 작동 중, 즉 애플리케이션 실행 시점에 발생할 수 있는 예외들의 상위 클래스이다.

  • RuntimeException은 Program 실행 중에 발생하며 System 환경적으로나, Input Value가 잘못된 경우, 의도적으로 개발자가 설정한 조건을 위배했을 때 throw 되게 하는 등, Application 실행 도중에 발생하는 Exception이다.
  • RuntimeException은 명시적으로 예외 처리를 하지 않아도 되는 Exception이다.
    • Exception 처리를 명시하지 않아도 Program 구동에 아무 문제가 없다.
    • 그러나 다른 문제를 야기할 수 있으니 처리할 수 있는 만큼 처리해주는 것이 좋다.

RuntimeException 과 ErrorClass들을 UnchckedException 이라고 묶으며,
RuntimeException 과 ErrorClass들을 제외한 예외 클래스들을 CheckedException로 묶는다,

 

CheckedException과 UncheckedException

CheckedException (확인된 예외)

RuntimeException을 상속받지 않은 클래스들을 CheckedExcpetion이라고 한다.

예외가 발생할 수 있는것이 확인되기 때문에 반드시 명시적으로 처리해야 한다.

CheckedException은 반드시 예외 처리 해야하는 Exception*으로, *Compile 시점에서 Exception 발생이 확인될 수 있으므로 반드시 명시적으로 처리해야 한다. 그렇지 않으면 컴파일러가 에러를 잡는다

  • 메소드 내에서 try catch를 하든, 메소드 밖으로 throws를 통해서 던져서 명시적으로 처리해야 한다.
    • 이것은 문법적으로 강제적이다.
  • CheckedException은 `Error와 RuntimeException을 상속받지 않은 Exception 들을 모두 포함한다.
    • Error, FileNotFoundException, ClassNotFoundException

Spring @Transaction 어노테이션 Rollback 기본 정책이 Unchcked Exception과 error들이다.
즉 설정을 바꾸지 않으면 CheckedException은 Transaction 처리시에 Exception이 발생해도 Rollback을 하지 않는다.

하지만 어떤 예외가 발생하면 롤백을 할 것이냐 말 것이냐는 개발자가 정하는 것이다.

  • CheckedException들이 롤백이 안되는 것이 아니다.
  • @Transactional(rollbackFor=Exception.class) 옵션으로 모든 예외에 대해서 롤백할 수 있다.
  • Checked Exception을 try-catch문으로 더 구체적인 Unchecked Exception으로 감싸주면 롤백이 가능하다.

 

UncheckedException (확인되지 않은 예외)

RuntimeException을 상속받은 모든 예외 클래스들을 UnchckedException 이라고 한다.

예외가 발생할 수 있는 것이 확인되지 않기 때문에 처리할 방법을 고민해야 한다.

  • UncheckedException은 명시적으로 예외 처리 해주지 않아도 되는 Exception으로, **Runtime 시점에서 Exception 이 발생해야 확인되고, 컴파일 시점에는 확인되지 않는 예외이다.
  • 주로 프로그래머들의 실수나 예견되지 못한 값 처리 등, 잘못된 값 입력 등에 의해서 일어나는 예외이다.
    • 그러니까 확인되지 않은 예외(UncheckedException)이다.
  • UncheckedException은 RuntimeException을 상속받는 Exception들을 포함한다.
    • NullPointerException, ClassCastException, IllegalArgumentException 등

 

Spring @Trasactional 어노테이션과 Rollback에 관련된 checkedException과 UncheckedException의 고찰


스프링 트랜잭셔널 어노테이션 과 예외들의 관계들을 정리한 블로그들을 보고 백기선님 영상을 보니까 뭔가 잘못 공부하고 있단 생각을 들었다 

 

스프링프레임워크 @Transactionl 트랜잭션 사용 시 체크드 익셉션은 롤백 수행 x , 언체크드 익셉션은 롤백 수행 o

 

그런데 @Transactional 어노테이션 옵션을 보면 rollbackfor 와 같은 옵션들이 있다.

  • 특정한 예외를 잡으면 롤백이 되도록 설정하는것.

이 rollbackfor를 Exception.class 으로 잡으면 어떻게 될까?

  • 모든 Exception, 즉 CheckedException 까지 롤백을 하게 되는 것이다.

또한 noRollbackFor 라는 옵션이 있는데, 이걸로 특정 Unchecked Exception을 설정하게 되면?

  • 어떻게 될것인가?

그럼 다시 생각해보면 저 *@Transactionl 트랜잭션 사용 시 체크드 익셉션은 롤백 수행 x , 언체크드 익셉션은 롤백 수행 o *라는 말은 부정확한 의미가 된다.

Spring @Transactional의 예외 발생 시 기본 rollback을 수행하는 정책은 언체크드익셉션, 즉 RuntimeException과 그 하위 클래스들이고, 개발자가(우리) 비즈니스와 상황에 맞게 알맞게 처리할 수 있다.

개발자는 상황에 맞게 예외를 처리할 수 있어야 하며, 스프링 트랜잭션도 그렇게 할 수 있도록 옵션을 지원한다.

rollbackFor, noRollbackFor 등

다시한번 정리하자면

Spring @Transactional의 예외 발생 시 기본 rollback을 수행하는 정책은 UnchecedExceptiop, 즉 RuntimeException과 그 하위 클래스들이고, 개발자가(우리) 비즈니스와 상황에 맞게 알맞게 처리할 수 있게 rollbackFor, noRollbackFor. 옵션을 지원해 준다.

어디까지나 기본 정책이 체크드 익셉션은 롤백을 하지 않는것이고, 불가능한 것이 아니다.

스프링이 옵션을 제공하니까 우리는 그것을 알맞게 (상황에 맞게도 같은 말이 될 것 같다) 사용하면 되는 것이다.

우리는 문제는 상황에 맞게 다양하게 해결할 수 있어야 한다.

 

Checked Exception에서 Rollback이 안되는 이유

메소드 API를 설계할 때 해당 메소드 호출이 어떤 예외를 발생 시키는지 또한 API 규악의 중요한 내용이고, 때로는 그런 예외에 대한 처리를 호출자에게 강제할 수 있어야 한다는 뜻인 것 같다.

개발자가 컴파일 시 예측/처리 가능한 예외의 처리를 개발자에게 강제하기 위해 Checked Exception은 개발자가 처리하라 라는 뜻같다.

어노테이션을 사용하든 AOP에 설정을 하든 스프링은 Unchecked Exception(RuntimeException)과 Error 발생 시 롤백 적용을 기본 정책으로 한다.

@Override
public boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
}

스프링에서 제공하는 트랜잭션 설정 클래스 DefaultTransactionAttribute 의 메소드 rollbackOn를 보면 RuntimeException과 Error인 경우에 true를 반환한다.

또한 @Transactional 어노테이션의 옵션들을 보면

    /**
     * Defines zero (0) or more exception {@linkplain Class classes}, which must be
     * subclasses of {@link Throwable}, indicating which exception types must cause
     * a transaction rollback.
     * <p>By default, a transaction will be rolled back on {@link RuntimeException}
     * and {@link Error} but not on checked exceptions (business exceptions). See
     * {@link
     ...
     */
Class<? extends Throwable>[] rollbackFor() default {};
  • will be rolled back on {@link RuntimeException} and {@link Error} - 런타임 엑셥과 에러들 (언체크드 익셉션)
  • but not on checked exceptions (business exceptions). - 체크드 익셉션은 롤백 안함

@Transactional 어노테이션을 아무것도 설정하지 않은 default 사용하게 된다면 다음과 같이 기본 정책 적용된다

@Transactional(rollbackFor = {RuntimeException.class, Error.class})
public void save(AnyEntity entity) {
  ...
}

 

정리

컴파일 시점에~ CheckedException (확인되는 예외) UncheckedException (확인되지 않은 예외 )
확인 시점 Compile Runtime
처리 시점 반드시 예외 처리 명시적으로 하지 않아도 무관
예시 ClassNotFoundException RuntimeException, NPE

스프링 @Transactional을 사용해서 트랜잭션 안에서 예외가 발생할 시,

Rollback 처리되는 기본 정책의 예외들은 UncheckedException 이며 (RuntimeException, Error)

이 기본정책을 default로 사용하면 CheckedException들은 rollback 되지 않는다.

그러나 이 정책은 언제든지 변경할 수 있게 스프링에서
@Transactional( 옵션들 ) 에서 변경할 수 있고 개발자가 선택할 수 있으므로 상황에 맞게 적절하게 처리하면 된다.

  • noRollbackFor, rollbaclFor 등등

@Transactional API 문서

  • 이미지 참조
  • 참조
저작자표시 비영리 (새창열림)

'Java' 카테고리의 다른 글

Java - double brace (생성과 동시에 초기화, 함수호출)  (0) 2022.11.20
Java List to String array. 리스트를 스트링으로  (0) 2022.11.14
Java interface 사용 이유, interface의 장단점.  (2) 2022.09.29
Java 동시성 제어 - 멀티스레드, Syncronized, volatile, Atomic  (0) 2022.09.04
    'Java' 카테고리의 다른 글
    • Java - double brace (생성과 동시에 초기화, 함수호출)
    • Java List to String array. 리스트를 스트링으로
    • Java interface 사용 이유, interface의 장단점.
    • Java 동시성 제어 - 멀티스레드, Syncronized, volatile, Atomic
    ysk(0soo)
    ysk(0soo)
    백엔드 개발을 좋아합니다. java kotlin spring, infra 에 관심이 많습니다. email : kim206gh@naver.com github : https://github.com/devysk

    티스토리툴바