트랜잭션이란?
트랜잭션은 데이터베이스의 상태를 변경하고자 할 때, 한번에 수행되어야 하는 연산 단위를 의미합니다.
만약 연산 중 예외가 발생하면 **모든 작업을 롤백(rollback)**하여, 데이터의 일관성을 유지합니다.
예를 들어, 하나의 서비스 로직 안에서 A 엔티티와 B 엔티티의 값을 변경하던 중 에러가 발생한다면,
변경된 A 엔티티의 값도 원래 상태로 되돌려야 합니다.
이를 위해 트랜잭션은 ACID(Atomicity, Consistency, Isolation, Durability) 원칙을 따릅니다.
👉 트랜잭션의 주요 기능
- Atomicity(원자성): 작업이 모두 성공하거나 모두 실패해야 함
- Consistency(일관성): 트랜잭션이 끝난 후 데이터는 항상 일관된 상태여야 함
- Isolation(고립성): 동시에 실행되는 트랜잭션 간에 간섭이 없어야 함
- Durability(지속성): 트랜잭션이 완료되면 그 결과는 영구적으로 반영
👉 @Transactional 어노테이션
트랜잭션 처리를 위해 Spring에서는 @Transactional 애노테이션을 사용합니다.
특히, 데이터가 바뀌는 CUD(Create, Update, Delete) 작업에 자주 사용됩니다.
@Transactional의 readOnly 속성이란?
**readOnly = true**는 트랜잭션을 읽기 전용으로 설정하는 옵션입니다.
이 옵션은 기본적으로 데이터베이스에 변경 작업(CUD)이 없고, 읽기만 수행하는 메서드에 적용됩니다.
👉 왜 사용하는가?
- 의도치 않은 데이터 변경 방지: 데이터를 조회만 해야 하는 메서드에서 실수로 변경 작업이 수행되지 않도록 보호.
- 성능 최적화: 변경 감지(Dirty Checking)를 비활성화하여 불필요한 연산을 줄임. Hibernate 세션의 Flush 모드를 MANUAL로 설정하여, 데이터베이스에 쓰기 작업을 하지 않음.
- 직관적인 코드: 해당 메서드가 읽기 작업만 수행한다는 의도를 명확히 표현.
👉 성능 최적화가 되는 이유
- 변경 감지 비활성화: 엔티티의 변경 사항을 추적하기 위한 스냅샷 저장이 필요 없어 메모리와 연산 오버헤드 감소.
- Flush 방지: Hibernate는 기본적으로 트랜잭션 커밋 시 변경 사항을 데이터베이스에 반영(Flush)하지만, readOnly = true에서는 Flush를 수행하지 않음.
Hibernate 세션의 Flush란?
Hibernate는 객체를 데이터베이스와 동기화하기 위해 Flush라는 과정을 수행합니다.
Flush는 영속성 컨텍스트(Persistence Context)에 있는 변경 사항을 데이터베이스에 반영하는 작업입니다.
👉 readOnly = true 시 효과
- Hibernate의 세션 Flush 모드가 MANUAL로 설정되어, 트랜잭션 커밋 시에도 변경 사항을 데이터베이스에 반영하지 않음.
- 읽기 작업에 불필요한 연산이 생략되므로 성능이 향상됩니다.
실제 사용 시 주의사항
- 데이터 변경 작업이 없어야 함: readOnly = true는 조회 작업에만 사용해야 하며, 변경 작업이 포함된 경우 데이터베이스에 반영되지 않을 수 있음.
- 주요 사용 사례: 조회 쿼리, 리포팅 작업, 대용량 데이터 읽기 등
- 코드에서 명확히 표현: readOnly = true를 통해 코드의 의도를 명확히 하고, 팀원들이 메서드의 용도를 쉽게 이해하도록 도움.
마무리
@Transactional(readOnly = true)는 단순히 읽기 작업에 사용하는 것뿐 아니라,
데이터베이스 성능을 최적화하고, 코드의 가독성을 높이는 데 중요한 역할을 합니다.
Spring과 JPA를 사용하는 환경에서는, 조회 작업을 할 때 반드시 readOnly = true를 사용하는 습관을 들이는 것이 좋습니다.
'Backend > Spring & Spring Boot' 카테고리의 다른 글
Principal 객체 (0) | 2024.01.23 |
---|---|
영속성 컨텍스트 (0) | 2023.11.22 |