반응형
해당 글에서는 @Transactional 어노테이션에 대해 상세한 이해를 돕기 위해 작성한 글입니다.
💡 [참고] 다양한 Annotation에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
구분 | 링크 |
Spring Web Annotation : 환경 구성 | https://adjh54.tistory.com/311 |
Spring Web Annotation : 요청 및 응답 | https://adjh54.tistory.com/312 |
Spring Web Annotation : 예외처리 및 주입 | https://adjh54.tistory.com/313 |
1) @Transactional
💡 @Transactional
- 스프링 프레임워크에서 특정 메서드 또는 클래스에서 수행되는 ‘트랜잭션’과 관련되어 관리를 위해서 사용되는 어노테이션입니다.
- 메서드 또는 클래스에 해당 어노테이션을 선언하면 코드 실행 중에 트랜잭션에 오류가 발생되면 트랜잭션이 '롤백'되고 변경 사항이 모두 취소됩니다.
- 해당 어노테이션을 ‘org.springframework.boot:spring-boot-starter-web' 를 추가하면 사용 가능합니다.
[ 더 알아보기 ]
💡 트랜잭션
- 데이터베이스 작업을 '원자적으로 처리'하기 위한 메커니즘을 의미합니다.
- 여러 개의 데이터베이스 작업을 하나의 논리적 단위로 묶어서 실행하고 모든 작업이 성공적으로 완료하면 '커밋'하거나 실패할 경우 '롤백'하는 기능을 제공합니다.
💡 원자적으로 처리한다는 말은 무슨말일까?
- 트랜잭션 내의 모든 데이터베이스 작업이 모두 성공하거나 모두 실패할 때까지 어떤 작업도 부분적으로 적용되지 않는다는 것을 의미합니다.
- 다시 말해, 트랜잭션은 모든 작업이 완전히 수행되기 전까지는 어떤 변화도 발생하지 않도록 보장합니다.
1. @Trasnactional 이점
💡 @Trasnactional 이점
1. 자동으로 트랜잭션을 시작하고 커밋 또는 롤백할 수 있습니다.
2. 트랜잭션 경계를 명시적으로 설정할 필요가 없습니다.
3. 예외 발생 시 롤백이 처리됩니다.
2. @Transactional 속성
💡 @Transactional 속성
- @Transactional의 속성값에 대해 알아봅니다.
속성 | 설명 | 속성 값 |
propagation | 트랜잭션 전파 동작을 지정합니다. | REQUIRED, SUPPORTS, MANDATORY, REQUIRES_NEW, NOT_SUPPORTED, NEVER, NESTED |
isolation | 트랜잭션 격리 수준을 지정합니다. | DEFAULT, READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE |
timeout | 트랜잭션 제한 시간을 지정합니다. | 초 단위의 정수 값 |
readOnly | 트랜잭션이 읽기 전용인지 지정합니다. | true, false |
rollbackFor | 롤백을 일으키는 예외를 지정합니다. | 예외 클래스 |
noRollbackFor | 롤백을 일으키지 않는 예외를 지정합니다. | 예외 클래스 |
2.1. propagation 상세 속성
💡 propagation
- 트랜잭션 전파 동작을 지정합니다.
- 속성에 대한 설정을 하지 않으면 기본값으로 'Propagation.REQUIRED'를 가집니다.
propagation 상세 속성 값 | 설명 |
Propagation.REQUIRED | 현재 트랜잭션이 존재하면 그 트랜잭션 내에서 실행하고, 트랜잭션이 없으면 새로운 트랜잭션을 시작합니다. |
Propagation.SUPPORTS | 현재 트랜잭션이 존재하면 그 트랜잭션 내에서 실행하고, 트랜잭션이 없으면 트랜잭션 없이 실행합니다. |
Propagation.MANDATORY | 현재 트랜잭션이 존재하면 그 트랜잭션 내에서 실행하고, 트랜잭션이 없으면 예외를 발생시킵니다. |
Propagation.REQUIRES_NEW | 항상 새로운 트랜잭션을 시작하고, 현재 트랜잭션이 존재하면 일시정지시킵니다. |
Propagation.NOT_SUPPORTED | 트랜잭션 없이 실행하고, 현재 트랜잭션이 존재하면 일시정지시킵니다. |
Propagation.NEVER | 트랜잭션 없이 실행하고, 현재 트랜잭션이 존재하면 예외를 발생시킵니다. |
Propagation.NESTED | 현재 트랜잭션이 존재하면 중첩된 트랜잭션으로 실행하고, 트랜잭션이 없으면 REQUIRED와 같이 동작합니다. |
2.2. isolation 상세 속성
💡 isolation
- 트랜잭션 격리 수준을 지정합니다.
- 속성에 대한 설정을 하지 않으면 기본값으로 'Isolation.DEFAULT'를 가집니다.
- 각 격리 수준은 트랜잭션의 동시성과 데이터 일관성 사이에 트레이드오프를 제공합니다.
- 격리 수준을 선택할 때는 동시성이 필요한지, 데이터 일관성이 우선인지 등을 고려하여 적절한 격리 수준을 선택해야 합니다.
Isolation 속성 값 | 설명 |
Isolation.DEFAULT | 기본 격리 수준을 사용합니다. |
Isolation.READ_UNCOMMITTED | 커밋되지 않은 데이터에 대한 읽기를 허용합니다. |
Isolation.READ_COMMITTED | 커밋된 데이터만 읽기를 허용합니다. |
Isolation.REPEATABLE_READ | 같은 쿼리를 반복해서 실행할 때 같은 결과를 보장합니다. |
Isolation.SERIALIZABLE | 동시성 문제를 완전히 막기 위해 모든 트랜잭션을 순차적으로 처리합니다. |
2) 예외 처리(Exception)
💡 예외 처리(Exception)
- @Transactional 어노테이션을 통해 예외처리가 발생한 경우 '롤백'을 하기 위한 목적으로 사용되기에 간단한 예외처리에 대해 확인합니다.
[ 더 알아보기 ]
💡 롤백(rollback)
- 트랜잭션 내에서 어떤 작업이 실패했을 때, 이전 상태로 되돌리는 것을 말합니다. 즉, 트랜잭션 내의 작업 중 하나가 실패하면, 이전에 수행한 모든 작업을 취소하고 데이터베이스를 이전의 일관된 상태로 복원합니다.
- 이를 통해 데이터의 무결성을 유지하고, 오류가 발생한 상태를 회복할 수 있습니다.
1. 확인된 예외처리(Checked Exception)
💡 확인된 예외처리(Checked Exception)
- ‘프로그램에서 반드시 처리해야 하는 예외’를 의미합니다. 이러한 예외는 컴파일러에 의해 강제로 처리되어야 하며 예외 처리를 하지 않으면 컴파일 오류가 발생합니다.
- 확인된 예외는 주로 입출력(IO) 작업, 네트워크 통신, 데이터베이스 연결 등과 관련된 작업에서 발생할 수 있습니다.
확인된 예외처리(Checked Exception) 종류 | 설명 |
IOException | 입출력 작업 중 발생하는 예외 |
SQLException | 데이터베이스 관련 작업 중 발생하는 예외 |
ClassNotFoundException | 클래스를 찾을 수 없을 때 발생하는 예외 |
InterruptedException | 스레드가 중단될 때 발생하는 예외 |
IllegalAccessException | 클래스의 멤버에 접근할 수 없을 때 발생하는 예외 |
NoSuchMethodException | 호출하려는 메서드가 존재하지 않을 때 발생하는 예외 |
NoSuchFieldException | 참조하려는 필드가 존재하지 않을 때 발생하는 예외 |
FileNotFoundException | 파일을 찾을 수 없을 때 발생하는 예외 |
ParseException | 문자열을 파싱할 때 발생하는 예외 |
MalformedURLException | 잘못된 URL이 주어졌을 때 발생하는 예외 |
2. 확인되지 않은 예외처리(Unchecked Exception)
💡 확인되지 않은 예외처리(Unchecked Exception)
- 프로그램에서 반드시 처리하지 않아도 되는 예외를 말합니다. 이러한 예외는 컴파일러가 강제로 예외 처리를 요구하지 않으며, 개발자의 선택에 따라 처리할 수도, 처리하지 않을 수도 있습니다.
- 확인되지 않은 예외는 주로 프로그래밍 오류, 논리 오류, 런타임 환경의 문제 등에서 발생할 수 있습니다.
확인되지 않은 예외처리(Unchecked Exception) 종류 | 설명 |
NullPointerException | 객체가 예상되는 자리에 null 참조가 사용될 때 발생 |
ArrayIndexOutOfBoundsException | 잘못된 인덱스로 배열에 접근하려고 할 때 발생 |
ClassCastException | 요청된 타입과 호환되지 않는 객체가 있을 때 발생 |
IllegalArgumentException | 메소드의 인수가 잘못된 경우 발생 |
IllegalStateException | 객체의 상태가 요청된 작업에 부적합한 경우 발생 |
UnsupportedOperationException | 지원되지 않는 작업이 호출될 때 발생 |
NumberFormatException | 문자열을 숫자 값으로 변환할 수 없는 경우 발생 |
💡 [참고] 예외처리에 대해 더 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
3) @Transactional 예외처리에 대한 롤백 범위
1. @Transactional 롤백 범위
💡 API 문서를 확인해 보면
‘기본적으로 트랜잭션은 RuntimeException 및 오류가 발생하면 롤백되지만 확인된 예외는 롤백되지 않습니다.(By default, a transaction will be rolled back on RuntimeException and Error but not on checked exceptions)’
이라고 이야기하고 있습니다.
💡 즉, RuntimeException의 경우 예외처리 중 ‘Unchecked Exception’에 해당하며 ‘Checked Exception’의 경우에는 롤백을 수행하지 않는다고 합니다.
💡 아래의 계층도를 확인해보면 Checked Exception과 RuntimeException에 해당하는 ‘Unchekced Exception’ 두 가지로 나뉩니다.
2. Checked Exception의 Transcation 테스트 : rollbackFor 속성을 추가하지 않은 경우
💡 Checked Exception의 Transcation 테스트 : rollbackFor 속성을 추가하지 않은 경우
💡사용예시
- 아래의 예시에서는 INSERT를 하는 트랜잭션이 포함되어 있는 ServiceImpl 중 하나입니다.
- 소스코드 중에 INSERT를 수행하고 강제로 Checked Exception을 발생하도록 IOException를 수행하였습니다.
/**
* 코드를 추가합니다.
*
* @param codeDto CodeDto
* @return int
*/
@Transactional
public int insertCode(CodeDto codeDto) throws IOException {
int result = 0;
CodeMapper cm = sqlSession.getMapper(CodeMapper.class);
try {
cm.insertCode(codeDto); // 트랜잭션을 수행합니다.
// FIXME: 강제로 확인된 Exception을 수행합니다.
throw new IOException("This is a forced IOException");
} catch (RuntimeException e) {
throw new BusinessExceptionHandler(e.getMessage(), ErrorCode.INSERT_ERROR);
}
}
💡 사용예시
- 아래와 같이 API 호출을 하였을 때 강제로 오류를 수행했기에 오류가 발생하였습니다.
💡 사용예시 결과
- 아래와 같이 INSER는 수행되었습니다. 그리고 이후 IOException을 발생하여 오류가 나왔습니다.
💡 사용예시 결과
- 그러나 아래와 같이 트랜잭션이 발생하여 INSERT가 수행되었고 롤백이 수행되지 않아 오류가 발생하였지만 데이터가 INSERT가 되었습니다.
4. Checked Exception의 Transcation 테스트 : rollbackFor 속성을 추가한 경우
💡 Checked Exception의 Transcation 테스트 : rollbackFor 속성을 추가한 경우
- default로 RuntimeException이 지정되어 있기에 추가로 Exception을 포함하면 Checked Exception이 발생하더라도 롤백이 수행됩니다.
- 이를 위해서 rollbackFor 속성을 통해 ‘롤백을 일으키는 예외를 지정’합니다.
- Exception을 추가함으로써 최상위 예외처리로 Checked Exception과 Unchecked Exception를 함께 롤백 처리하도록 구성이 가능합니다.
💡 사용예시
- 아래의 예시에서는 INSERT를 하는 트랜잭션이 포함되어 있는 ServiceImpl 중 하나입니다.
- 소스코드 중에 INSERT를 수행하고 강제로 Checked Exception을 발생하도록 IOException를 수행하였습니다.
- 위와 동일한 예시이지만 rollbackFor 속성으로 Exception.class에 대해 롤백을 수행하도록 추가하였습니다.
/**
* 코드를 추가합니다.
*
* @param codeDto CodeDto
* @return int
*/
@Transactional(rollbackFor = Exception.class)
public int insertCode(CodeDto codeDto) throws IOException {
int result = 0;
CodeMapper cm = sqlSession.getMapper(CodeMapper.class);
try {
cm.insertCode(codeDto); // 트랜잭션을 수행합니다.
// FIXME: 강제로 확인된 Exception을 수행합니다.
throw new IOException("This is a forced IOException");
} catch (RuntimeException e) {
throw new BusinessExceptionHandler(e.getMessage(), ErrorCode.INSERT_ERROR);
}
}
💡 사용예시
- 아래와 같이 API 호출을 하였을때 강제로 오류를 수행했기에 오류가 발생하였습니다.
💡 사용예시 결과
- 아래와 같이 INSER는 수행되었습니다. 그리고 이후 IOException을 발생하여 오류가 나왔습니다.
💡 사용예시 결과
- 위에 수행된 구문이 출력이 되었지만, 실제로 트랜잭션이 롤백이 되어서 INSERT 되지 않았습니다.
- 그러나 아래와 같이 트랜잭션이 발생하여 INSERT가 수행되었고 롤백이 수행되지 않아 오류가 발생한 데이터가 INSERT가 되었습니다.
오늘도 감사합니다. 😀
반응형
'Java > 이론 및 문법' 카테고리의 다른 글
[Java] JDBC, DBCP, JNDI 이해하기 : 주요기능, 처리과정 (3) | 2024.02.21 |
---|---|
[Java] Enum(Enumerated type) : 열거형 이해하기 -1 : 정의, 주요특징, 메서드, 활용 예시 (0) | 2024.02.16 |
[Java] 예외처리(Exception Handling) 이해하기 -1 : try - catch / throws (0) | 2023.12.24 |
[Java] 접근 제한자/제어자(Access Modifier) 이해하기 : public, private, protected, default (0) | 2023.12.24 |
[Java] API 캐시와 세션 이해하기 (1) | 2023.10.22 |