[JPA] @Transactional
- 🌿 Spring Framework/JPA
- 2025. 9. 23.
트랜잭션이란?
트랜잭션은 데이터베이스의 상태를 변경시키는 더 이상 쪼개질 수 없는 최소한의 작업 단위이다.
회원가입을 예시로 들어보자.
다음 예제는 총 4가지 작업으로 구성된다.
1. validateUserUniqueness - 사용자 이름과 이메일이 디비에서 중복되지 않는지 검사한다.
2. encodePassword - 패스워드를 암호화한다.
3. 유저 객체를 생성한다.
4. 유저 레포지토리에 저장한다.
public User createUser(String username, String password, String email) {
validateUserUniqueness(username, email);
String encodedPassword = passwordEncoder.encode(password);
User user = new User(username, encodedPassword, email);
return userRepository.save(user);
}
4가지 작업이 모두 성공적으로 완료되어야만 회원가입이 정상적으로 처리된 것이다.
만약 3번 (유저 객체 생성) 로직 까지만 수행되고 4번 (유저 레포지토리에 저장) 하는 로직이 정상적으로 수행되지 않았다면, 메모리 누수가 발생할 것이다.
따라서 트랜잭션은 4가지 작업을 하나의 묶음으로 처리해 하나라도 실패하면 모두 이전 상태로 되돌리는 Rollback을 보장한다.
ACID
트랜잭션은 ACID라는 4가지 특성을 통해서 데이터의 일관성을 보장한다.
1. 원자성 (Atomicity) - 트랜잭션의 모든 작업이 전부 성공하거나 전부 실패하는 것을 보장한다.
2. 일관성 (Consistency) - 트랜잭션이 성공되었다면 데이터베이스는 일관성 있는 상태를 유지한다.
3. 고립성 (Isolation) - 하나의 트랜잭션이 실행 중일때 다른 트랜잭션이 영향을 주지 못하도록 격리한다.
4. 지속성 (Durability) - 성공적으로 수행된 트랜잭션은 시스템에 영구적으로 저장되어야 한다.
@Transactional
Spring은 이러한 트랜잭션을 개발자가 쉽게 사용할 수 있도록 Transactional Annotation을 제공한다.
@Transactional은 클래스 단위에 사용하거나 메소드 단위에 사용할 수 있으며
클래스 단위에 붙여주면 해당 클래스의 메서드는 모두 하나의 트랜잭션 안에서 실행된다.
만약 메소드 실행 중 예외가 터진다면 스프링이 자동으로 rollback을 수행한다.
@Service
@Transactional // 클래스 단위 수행
public class UserService {
...
// 메서드 단위 수행
@Transactional
public User createUser(String username, String password, String email) {
validateUserUniqueness(username, email);
String encodedPassword = passwordEncoder.encode(password);
User user = new User(username, encodedPassword, email);
return userRepository.save(user);
}
...
@Transactional
public User updateUser(User user) {
return userRepository.save(user);
}
}
readOnly
@Transactional 에는 다양한 속성이 존재하는데 그중 readOnly 속성을 잘 사용하면 성능을 최적화할 수 있다.
readOnly 속성의 Default 값은 false이며, readOnly 속성을 True로 설정하면 해당 트랜잭션 내부의 데이터는 읽기 전용으로 세팅된다.
readOnly 속성이 붙은 트랜잭션은 불필요한 오버헤드 (스냅샷, 프록시 등..) 를 줄여 성능 향상에 도움이 되며, 데이터의 일관성 또한 지킬 수 있다.
따라서 단순 조회 메서드는 readOnly 속성을 true로 설정하도록 하자.
// 사용자명 중복 확인
@Transactional(readOnly = true)
public boolean existsByUsername(String username) {
return userRepository.existsByUsername(username);
}
/// 이메일 중복 확인
@Transactional(readOnly = true)
public boolean existsByEmail(String email) {
return userRepository.existsByEmail(email);
}
'🌿 Spring Framework > JPA' 카테고리의 다른 글
[JPA] Embedded, Embeddable annotation & Refactoring Example (0) | 2025.09.21 |
---|