📌
@Transactional은 스프링 프레임워크에서 제공하는 어노테이션으로, 트랜잭션 관리를 선언적으로 적용할 수 있도록 도와줍니다.
데이터베이스의 상태를 일관되게 유지하고 작업 도중 문제가 발생했을 때 데이터를 롤백하여 안정성을 보장하는데 사용됩니다.
트랜잭션은 데이터베이스의 논리적 작업 단위로, 다음 4가지 속성을 가집니다(ACID).
스프링은 @Transactional을 적용하기 위해 AOP(Aspect-Oriented Programming)와 프록시(proxy)를 사용합니다:
@Transactional이 선언된 클래스 또는 메서드에 대해 스프링이 프록시 객체를 생성합니다.커밋(commit)합니다.롤백(rollback)합니다.@Transactional에는 다양한 속성을 지정하여 트랜잭션의 동작을 제어할 수 있습니다.
트랜잭션이 실행되는 방식을 제어합니다. 주요 옵션:
REQUIRED (기본값): 현재 트랜잭션이 있으면 참여하고, 없으면 새로운 트랜잭션을 시작합니다.
REQUIRES_NEW : 항상 새로운 트랜잭션을 시작하며, 기존 트랜잭션은 일시 정지됩니다.
NESTED : 기존 트랜잭션 내부에 중첩된 트랜잭션을 생성합니다.
MANDATORY : 반드시 기존 트랜잭션이 있어야 하며, 없으면 예외가 발생합니다.
SUPPORTS : 트랜잭션이 있으면 참여하고, 없으면 트랜잭션 없이 실행합니다.
NOT_SUPPORTED : 트랜잭션 없이 실행하며, 기존 트랜잭션은 일시 정지됩니다.
NEVER : 트랜잭션이 있으면 예외를 발생시킵니다.
트랜잭션 간 데이터 접근 방식을 설정합니다. 주요 옵션:
DEFAULT : 데이터베이스의 기본 격리 수준을 따릅니다.
READ_UNCOMMITTED: 다른 트랜잭션에서 커밋되지 않은 데이터를 읽을 수 있습니다.
READ_COMMITTED : 커밋된 데이터만 읽습니다(기본값).
REPEATABLE_READ : 트랜잭션이 진행되는 동안 동일한 데이터를 반복해서 읽어도 항상 같은 값이 보장됩니다.
SERIALIZABLE : 가장 엄격한 수준으로, 트랜잭션 간 완전한 고립을 보장합니다.
rollbackFor : 특정 예외가 발생하면 롤백합니다.
@Transactional(rollbackFor = CustomException.class)
noRollbackFor : 특정 예외가 발생해도 롤백하지 않습니다.
@Transactional(noRollbackFor = CustomException.class)
true : 데이터 읽기 전용 작업을 지정합니다(최적화).
false (기본값): 읽기/쓰기 작업을 허용합니다.
트랜잭션이 실행될 수 있는 최대 시간을 초 단위로 설정합니다. 기본값은 무제한입니다.
클래스에 @Transactional을 붙이면 모든 메서드에 트랜잭션이 적용됩니다.
@Service
@Transactional
public class MyService {
public void someMethod() {
// 트랜잭션이 적용됨
}
}
특정 메서드에만 트랜잭션을 적용합니다.
@Service
public class MyService {
@Transactional
public void someMethod() {
// 트랜잭션이 적용됨
}
public void anotherMethod() {
// 트랜잭션이 적용되지 않음
}
}
RuntimeException과 그 하위 클래스가 발생하면 롤백됩니다.
CheckedException은 기본적으로 롤백되지 않습니다.
@Transactional(rollbackFor = Exception.class)
public void someMethod() throws Exception {
// Exception 발생 시 롤백
}
@Transactional이 적용된 메서드를 같은 클래스 내에서 호출하면 프록시를 거치지 않아 트랜잭션이 적용되지 않습니다.트랜잭션 격리 수준이나 롤백 동작은 사용하는 데이터베이스에 따라 다를 수 있습니다.
readOnly = true로 설정했더라도 일부 데이터베이스는 쓰기 작업을 허용합니다. 개발자가 이를 직접 검증해야 합니다.📌
@Transactional은 트랜잭션 관리를 간소화하고 데이터베이스의 일관성을 유지하는 데 필수적입니다. 올바른 전파, 격리 수준, 예외 처리 설정을 통해 안정적이고 효율적인 애플리케이션을 개발할 수 있습니다. 하지만 트랜잭션이 항상 성능 부담을 동반하므로 필요하지 않은 경우에는 사용을 피하는 것이 좋습니다.