팝핀(Poppin) 프로젝트 회고
@Transactional이 무분별하게 사용되는 것을 방지하고자 트랜잭션 최적화 작업을 일부 수행했다.
@Transactional
특정 메서드나 클래스에서 수행되는 트랜잭션 관리를 위해 사용하는 어노테이션이다.
해당 어노테이션을 선언하면 런타임 중 트랜잭션에 오류가 발생하면 트랜잭션이 롤백(rollback)되고 변경 사항이 모두 취소된다.
이는 트랜잭션의 ACID 성질 중 원자성(Atomicity)과 관련이 있다.
여러 개의 작업을 하나로 묶은 논리적 단위가 트랜잭션이 되는데 이 작업들 중 하나라도 실패하면 모든 작업을 실패한 것으로 간주하고 트랜잭션이 실행되기 전으로 돌아간다.
반면, 모든 작업이 성공하면 커밋(commit)되고 변경사항이 반영된다.
둘 중 어느 것을 사용해야 할까❓
Spring boot를 사용하면서 @Transactional 어노테이션을 쓰게 된다면, 언젠가 두 가지 종류가 있다는 것을 알게 된다.
- @org.springframework.transaction.annotation.Transactional
- @jakarta.transaction.Transactional
해당 프로젝트에서는 Spring Framework에서 지원하는 @Transactional(@org.springframework.transaction.annotation.Transactional) 어노테이션을 사용했다.
두 어노테이션 모두 동일한 기본 기능을 제공하지만, Spring에서 지원하는 @Transactional이 더 많은 부가 기능을 가지고 있다.
실제로 @Transactional(readOnly = true)와 같이 readOnly 옵션을 사용해서 트랜잭션 최적화를 하고 싶은데 @jakarta.transaction.Transactional에는 없다. (readOnly 옵션을 사용하면 성능상 이점이 존재한다.)
@Transactional은 언제❓
어쨌든 @Transactional은 Create, Update, Delete에만 쓰는 거 아닌가? 생각할 수 있는데 조회용(Read) 메서드에서도 사용해야 할 시점이 온다. 사용하지 않게 된다면 다음과 같은 에러를 마주하게 된다.
org.hibernate.LazyInitializationException: could not initialize proxy [com.poppin.poppinserver.domain.User#3] - no Session
@ManyToOne(fetch = FetchType.LAZY)
지연 로딩(Lazy Loading) 설정된 연관 데이터를 세션이 종료된 후에 접근하려고 할 때 발생한다. 트랜잭션이 제대로 설정되지 않으면, 서비스 계층에서 데이터를 로드할 때 세션이 제대로 유지되지 않을 수 있다.
Hibernate는 연관된 엔티티나 컬렉션을 처음에는 실제로 로드하지 않고, 필요한 시점에 로드하는 방식을 사용한다. 예를 들어, User 엔티티의 연관된 데이터가 지연 로딩으로 설정되어 있을 경우, 해당 데이터는 실제로 접근하는 시점에 데이터베이스에서 조회된다.
@Transactional 은 메서드 실행 중 트랜잭션을 열고, 메서드가 끝날 때 트랜잭션을 종료하여 세션을 관리한다. 이를 통해 지연 로딩된 데이터가 트랜잭션 내에서 안전하게 로드될 수 있다.
@Transcational(readOnly = true)를 사용한 이유
그렇다면 이러한 조회용 메서드에 @Transcational을 붙여야 하는가? 이는 무분별한 사용이라고 생각한다. @Transactional(readOnly = true)를 사용하면 일부 성능 최적화를 수행할 수 있다.
@Transactional(readOnly = true)를 사용하면, 데이터베이스에 대한 쓰기 작업(INSERT, UPDATE, DELETE 등)이 불가능하도록 설정된다. 이로 인해 Hibernate는 세션에서 데이터를 변경하지 않을 것으로 간주하고, 더티 체킹(dirty checking)을 생략하여 불필요한 성능 오버헤드를 줄일 수 있다.
또한, 메서드의 트랜잭션이 오직 읽기 전용임을 명시적으로 선언함으로써, 코드의 의도를 명확히 할 수 있다.
이는 유지보수성을 높이고, 코드 리뷰나 협업 시 의사소통을 원활하게 해줄 것이다.
이 정도면 최적화라고 할 수 있지 않을까?
결론
그래서 몇몇 무분별하게 @Transactional이 박혀 있는 조회용 메서드에 readOnly = true 옵션을 주었다. 실제로 ms를 측정해서 성능 변화를 확인하고 싶은데 실제 환경에서 돌아가고 있는 서버고… dev 서버는 아직 구축이 되지 않았다. 로컬에서 하자니 데이터가 많지도 않고 일일이 다 넣어줘야 하는 불편함이 있다. 나중에 잊지말고 테스트해서 결과를 남겨야 겠다.
Reference
https://velog.io/@yarogono/JPA-could-not-initialize-proxy-no-Session-%EC%97%90%EB%9F%AC
https://cantcoding.tistory.com/78
'project > poppin-server' 카테고리의 다른 글
| 개발계 Jar 파일 배포 에러 - no main manifest attribute (0) | 2024.09.07 |
|---|---|
| Refresh Token Rotation을 통한 보안 강화 (0) | 2024.08.01 |