
트랜잭션(Transaction)**과 @Transactional 어노테이션은 데이터베이스의 일관성을 보장하고, 원자성을 유지하기 위해 중요한 역할을 함. 트랜잭션은 데이터베이스 작업을 하나의 단위로 처리하며, 모든 작업이 성공적으로 완료되거나, 그렇지 않으면 모두 롤백되도록 함. Spring에서 @Transactional 어노테이션은 트랜잭션을 선언적으로 관리할 수 있게 해주는 도구임.
트랜잭션은 데이터베이스에서 일련의 작업이 성공 또는 실패로 끝나야 하는 단위 작업을 의미함. 즉, 트랜잭션 내의 모든 작업이 성공해야만 커밋되고, 하나라도 실패하면 롤백되어 데이터베이스가 원래 상태로 돌아감. 이로 인해 데이터의 일관성과 무결성을 보장할 수 있음.
트랜잭션은 ACID(Atomicity, Consistency, Isolation, Durability)라는 4가지 특성을 가짐
@Transactional 어노테이션은 Spring에서 트랜잭션을 선언적으로 관리하기 위한 방법임. 이 어노테이션을 사용하면, 트랜잭션이 자동으로 시작되고 종료되며, 트랜잭션 내에서 발생하는 예외에 따라 커밋 또는 롤백이 자동으로 처리됨.
트랜잭션을 자동으로 시작하고, 메소드가 성공적으로 종료되면 커밋함.
메소드 실행 중 런타임 예외(비체크 예외, unchecked exception)가 발생하면 자동으로 롤백함.
체크 예외(checked exception)가 발생할 경우에는 기본적으로 롤백되지 않음. 필요하다면 설정을 통해 롤백하도록 지정할 수 있음.
@Transactional 어노테이션은 클래스 레벨 또는 메소드 레벨에서 선언할 수 있음. 해당 어노테이션이 적용된 범위에서 트랜잭션이 처리됨.
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void registerUser(User user) {
userRepository.save(user);
// 이 메소드 내의 모든 작업이 트랜잭션 내에서 처리됨
}
}
@Transactional이 붙은 registerUser 메소드에서 발생하는 모든 데이터베이스 작업은 하나의 트랜잭션으로 처리됨.
런타임 예외가 발생하면 롤백되고, 성공적으로 완료되면 커밋됨.
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
public void registerUser(User user) {
userRepository.save(user);
}
public void updateUser(User user) {
userRepository.save(user);
}
}
클래스 레벨에 @Transactional을 적용하면, 해당 클래스의 모든 메소드가 트랜잭션 관리하에 실행됨.
@Transactional은 다양한 속성을 제공하여 트랜잭션의 동작을 제어할 수 있음.
트랜잭션의 전파 행동을 정의함. 즉, 트랜잭션이 이미 진행 중일 때 새롭게 호출된 메소드가 새 트랜잭션을 시작할지 또는 기존 트랜잭션을 사용할지 결정함.
주요 옵션:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveUser(User user) {
userRepository.save(user); // 항상 새 트랜잭션에서 처리
}
트랜잭션에서 격리 수준을 설정함. 이는 동시성 문제를 처리하는 방법을 결정함.
주요 옵션:
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void updateUser(User user) {
userRepository.save(user); // REPEATABLE_READ 격리 수준에서 실행
}
트랜잭션이 지정된 시간 안에 완료되지 않으면 롤백되도록 설정함.
기본값은 -1로, 시간 제한이 없음을 의미함.
@Transactional(timeout = 5) // 5초 안에 트랜잭션이 완료되지 않으면 롤백
public void saveUser(User user) {
userRepository.save(user);
}
트랜잭션을 읽기 전용 모드로 설정하여, 조회 작업에만 사용하고 데이터 변경 작업은 금지함.
성능 최적화를 위해, 데이터베이스에서 읽기 전용 트랜잭션일 때 쓰기 잠금 등의 불필요한 리소스를 줄임.
@Transactional(readOnly = true)
public List<User> getUsers() {
return userRepository.findAll(); // 데이터 변경 불가, 조회만 가능
}
특정 예외 발생 시 트랜잭션을 롤백하도록 설정할 수 있음.
기본적으로는 체크 예외가 발생하면 롤백되지 않고, 런타임 예외가 발생하면 롤백됨.
@Transactional(rollbackFor = Exception.class)
public void saveUser(User user) throws Exception {
userRepository.save(user);
if (user.getName() == null) {
throw new Exception("Name is required"); // 이 경우 롤백됨
}
}
롤백은 런타임 예외(unchecked exception)가 발생할 때만 자동으로 처리됨.
체크 예외는 기본적으로 롤백되지 않으므로, rollbackFor 속성을 사용하여 롤백 조건을 명시적으로 설정해야 함.
트랜잭션 경계 밖에서 예외가 발생하거나, 트랜잭션이 정상 종료되기 전에 강제로 flush가 호출되면, 트랜잭션이 올바르게 처리되지 않을 수 있음.