우노
[Kotlin] @Transactional 본문
@Transactional 이란?
- @Transactional은 Spring에서 트랜잭션 관리를 자동화해주는 강력한 애노테이션입니다.
- 메서드나 클래스에 선언하면, 트랜잭션이 시작되고 작업 완료 시 자동으로 커밋하거나 예외 발생 시 롤백됩니다.
1. 메서드 수준에서 사용
메서드가 실행되는 동안 트랜잭션이 시작됩니다.
@Service class UserService(private val userRepository: UserRepository) { @Transactional fun createUser(user: User): User { userRepository.save(user) // 트랜잭션 내 작업 return user // 트랜잭션 커밋 } }
2. 클래스 수준에서 사용
클래스에 선언하면 해당 클래스의 모든 메서드에 트랜잭션이 적용됩니다.
@Service @Transactional class UserService(private val userRepository: UserRepository) { fun createUser(user: User): User { userRepository.save(user) return user } fun updateUser(user: User): User { userRepository.save(user) return user } }
주요 옵션
- @Transactional은 다양한 옵션을 제공하여 트랜잭션 동작을 세밀하게 제어할 수 있습니다.
1. 전파 방식 (Propagation)
트랜잭션이 호출될 때, 기존 트랜잭션을 사용할지, 새로 생성할지 결정합니다.
REQUIRED: 기본값. 기존 트랜잭션이 있으면 사용하고, 없으면 새로 생성합니다.
REQUIRES_NEW: 항상 새 트랜잭션을 생성하고, 기존 트랜잭션은 일시 중단됩니다.
SUPPORTS: 기존 트랜잭션이 있으면 사용하고, 없으면 트랜잭션 없이 실행됩니다.
NOT_SUPPORTED: 트랜잭션 없이 실행하고, 기존 트랜잭션이 있으면 일시 중단됩니다.
MANDATORY: 기존 트랜잭션이 반드시 있어야 하며, 없으면 예외가 발생합니다.
NEVER: 트랜잭션 없이 실행하고, 기존 트랜잭션이 있으면 예외가 발생합니다.
NESTED: 중첩 트랜잭션을 생성하며, 독립적인 롤백이 가능합니다. (JDBC에서만 지원)
@Transactional(propagation = Propagation.REQUIRES_NEW) fun processPayment(payment: Payment) { // 항상 새로운 트랜잭션으로 실행 }
2. 격리 수준 (Isolation)
동시에 실행되는 트랜잭션 간 데이터 일관성을 유지하는 방법을 설정합니다.
DEFAULT: 데이터베이스의 기본 설정을 사용합니다. 일반적으로 READ_COMMITTED입니다.
READ_UNCOMMITTED: 커밋되지 않은 데이터도 읽을 수 있습니다. (Dirty Read 허용)
READ_COMMITTED: 커밋된 데이터만 읽을 수 있습니다. (Dirty Read 방지)
REPEATABLE_READ: 트랜잭션 동안 동일 데이터를 읽으면 항상 같은 값을 읽습니다. (Phantom Read 허용)
SERIALIZABLE: 가장 높은 격리 수준으로, 트랜잭션이 완전히 순차적으로 실행됩니다. (성능 저하 가능)
@Transactional(isolation = Isolation.REPEATABLE_READ) fun getAccountBalance(accountId: Long): BigDecimal { // 트랜잭션 내 동일 데이터의 일관성 유지 }
3. 읽기 전용 (ReadOnly)
데이터 조회만 수행하는 경우, 최적화를 위해 읽기 전용으로 설정합니다.
@Transactional(readOnly = true) fun getAllUsers(): List<User> { return userRepository.findAll() // 읽기 전용 작업 }
4. 타임아웃 (Timeout)
트랜잭션이 특정 시간 내 완료되지 않으면 롤백합니다.
@Transactional(timeout = 5) // 5초 초과 시 롤백 fun processLargeData() { // 오래 걸리는 작업 }
5. 롤백 조건 (RollbackFor, NoRollbackFor)
특정 예외에 대해 롤백 여부를 설정할 수 있습니다.
@Transactional(rollbackFor = [CustomException::class]) fun updateUser(user: User) { if (user.name.isEmpty()) { throw CustomException("Invalid user name") // 롤백 발생 } userRepository.save(user) }
주의사항
같은 클래스 내 메서드 호출
@Transactional은 Spring 프록시로 작동하므로, 같은 클래스 내 메서드 호출 시 적용되지 않습니다.
@Transactional fun methodA() { methodB() // 트랜잭션 적용되지 않음 }
Checked Exception
- 기본적으로 Checked Exception이 발생해도 트랜잭션은 롤백되지 않습니다.
- 롤백을 원하면 rollbackFor를 명시적으로 설정해야 합니다.
요약
- @Transactional은 데이터의 일관성과 안정성을 보장하며, 트랜잭션 관리를 쉽게 해줍니다.
- 주요 옵션(전파 방식, 격리 수준, 읽기 전용 등)을 상황에 맞게 설정하면, 성능과 유지보수성을 동시에 확보할 수 있습니다.
- 기본 동작을 이해하고 적절히 설정하여 애플리케이션의 데이터 무결성을 유지하세요.
'Web_App > Kotlin' 카테고리의 다른 글
[Kotlin] @Transactional, Service vs Repository 어디에 적용할까? (0) | 2024.12.26 |
---|---|
[Kotlin] @Service vs @Component (2) | 2024.12.23 |
[Kotlin] Controller와 Service의 계층 구조 (0) | 2024.12.20 |
[Kotlin] @SqlResultSetMapping (0) | 2024.12.20 |
[Kotlin] ORM, JPA, Spring Data JPA (1) | 2024.12.18 |