- 스프링 프레임워크에서 특정 메서드 또는 클래스에서 수행되는 ‘트랜잭션’과 관련되어 관리를 위해서 사용되는 어노테이션입니다.
- 메서드 또는 클래스에 해당 어노테이션을 선언하면 코드 실행 중에 트랜잭션에 오류가 발생되면 트랜잭션이 '롤백'되고 변경 사항이 모두 취소됩니다. - 해당 어노테이션을 ‘org.springframework.boot:spring-boot-starter-web' 를 추가하면 사용 가능합니다.
[ 더 알아보기 ]
💡 트랜잭션
- 데이터베이스 작업을 '원자적으로 처리'하기 위한 메커니즘을 의미합니다. - 여러 개의 데이터베이스 작업을 하나의 논리적 단위로 묶어서 실행하고 모든 작업이 성공적으로 완료하면 '커밋'하거나 실패할 경우 '롤백'하는 기능을 제공합니다.
💡 원자적으로 처리한다는 말은 무슨말일까?
- 트랜잭션 내의 모든 데이터베이스 작업이 모두 성공하거나 모두 실패할 때까지 어떤 작업도 부분적으로 적용되지 않는다는 것을 의미합니다. - 다시 말해, 트랜잭션은 모든 작업이 완전히 수행되기 전까지는 어떤 변화도 발생하지 않도록 보장합니다.
- 트랜잭션 전파 동작을 지정합니다. - 속성에 대한 설정을 하지 않으면 기본값으로 '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 어노테이션을 통해 예외처리가 발생한 경우 '롤백'을 하기 위한 목적으로 사용되기에 간단한 예외처리에 대해 확인합니다.
https://www.nextree.co.kr/p3239/
[ 더 알아보기 ]
💡 롤백(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) - 프로그램에서 반드시 처리하지 않아도 되는 예외를 말합니다. 이러한 예외는 컴파일러가 강제로 예외 처리를 요구하지 않으며, 개발자의 선택에 따라 처리할 수도, 처리하지 않을 수도 있습니다.
- 확인되지 않은 예외는 주로 프로그래밍 오류, 논리 오류, 런타임 환경의 문제 등에서 발생할 수 있습니다.
💡 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’ 두 가지로 나뉩니다.
https://www.nextree.co.kr/p3239/
2. Checked Exception의 Transcation 테스트 : rollbackFor 속성을 추가하지 않은 경우
💡 Checked Exception의 Transcation 테스트 : rollbackFor 속성을 추가하지 않은 경우
💡사용예시
- 아래의 예시에서는 INSERT를 하는 트랜잭션이 포함되어 있는 ServiceImpl 중 하나입니다. - 소스코드 중에 INSERT를 수행하고 강제로 Checked Exception을 발생하도록 IOException를 수행하였습니다.
/**
* 코드를 추가합니다.
*
* @param codeDto CodeDto
* @return int
*/@TransactionalpublicintinsertCode(CodeDto codeDto)throws IOException {
int result = 0;
CodeMapper cm = sqlSession.getMapper(CodeMapper.class);
try {
cm.insertCode(codeDto); // 트랜잭션을 수행합니다.// FIXME: 강제로 확인된 Exception을 수행합니다.thrownew IOException("This is a forced IOException");
} catch (RuntimeException e) {
thrownew 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)publicintinsertCode(CodeDto codeDto)throws IOException {
int result = 0;
CodeMapper cm = sqlSession.getMapper(CodeMapper.class);
try {
cm.insertCode(codeDto); // 트랜잭션을 수행합니다.// FIXME: 강제로 확인된 Exception을 수행합니다.thrownew IOException("This is a forced IOException");
} catch (RuntimeException e) {
thrownew BusinessExceptionHandler(e.getMessage(), ErrorCode.INSERT_ERROR);
}
}
💡 사용예시 - 아래와 같이 API 호출을 하였을때 강제로 오류를 수행했기에 오류가 발생하였습니다.
💡 사용예시 결과
- 아래와 같이 INSER는 수행되었습니다. 그리고 이후 IOException을 발생하여 오류가 나왔습니다.
💡 사용예시 결과 - 위에 수행된 구문이 출력이 되었지만, 실제로 트랜잭션이 롤백이 되어서 INSERT 되지 않았습니다. - 그러나 아래와 같이 트랜잭션이 발생하여 INSERT가 수행되었고 롤백이 수행되지 않아 오류가 발생한 데이터가 INSERT가 되었습니다.