-
Notifications
You must be signed in to change notification settings - Fork 0
8주차 일지 김규원
코드리뷰때 조회성 api 에 @Transactional(readOnly=True) 를 쓴 이유에 대해 질문을 한 적이 있습니다. 실제로 테스트해보면 어노테이션을 다는게 성능이 더 좋다는데, 그래도 트랜잭션에 대한 코스트가 있을텐데 왜 좋은지에 대해 이해를 할 수 없었습니다. 그럴거면 jpa 안쓰고 jdbc template 로 조회하는게 더 좋지 않을까?
찾아보니 @Transactional(readOnly=True) 를 쓰는 이유가 다음과 같았습니다.
- 1차 캐시 무효화 : jpa 의 1차 캐시를 쓰지않도록 하면서 성능 최적화 가능
- MySQL 읽기 전용 트랜잭션에 대한 최적화 : MySQL 5.6 버젼 이상부터는 읽기 전용 트랜잭션을 지원합니다. 읽기 전용 트랜잭션은 리소스를 최적화할 수 있습니다. (언두로그 생성 x, 트랜잭션 id 할당 x)
단점도 존재합니다. JPA 스냅샷 유지, db 커넥션을 더 오래 물고 있다는 단점이 있어 적절하게 판단을 해야될거 같습니다.
참고 https://dkswnkk.tistory.com/740
저는 상위 엔티티가 하위 엔티티를 fetch 해오는 일이 더 많다고 생각하기 때문에 OneToMany 를 쓰기 위해 양방향을 쓰자고 주장했었습니다. 다른 팀원분들과 이야기해보니 n+1 문제 때문에 지양하는게 좋다고 판단하게 되었습니다. 대신 ManyToOne 으로 단방향만 설정해두기로 했습니다. 프로젝트를 진행해보니 연관관계 주인을 조회할 수 있도록 한 ManyToOne 이 괜찮은거 같습니다.
어디에서 jpa entity 를 fetch 할건지, 언제 dto projection 를 할지에 대해 고민을 했었습니다. 코드리뷰를 통해 그 이유를 알게 되었습니다.
- 엔티티를 조회하면 연관관계의 주인이 아닌 쪽에서 조회하는 경우 연관관계의 주인을 체크하기 위한 추가적인 쿼리가 나간다는 단점
- projection 를 쓰면 필요한 데이터만 정확히 가져올 수 있다는 장점이 확실함
https://github.com/woowa-techcamp-2024/Team2-Dari/pull/68#discussion_r1720762305
jpa 는 쓰기 지연 저장소에서 모아둔 쿼리를 모두 실행할 때 코드 순서와 동일하지 않게 실행될 수 있습니다. 이는 외래키 제약조건 위반을 방지하기 위함이라고 합니다.
물론이죠. 외래 키와 관련된 내용을 예시를 통해 설명해드리겠습니다. 예를 들어, 우리가 '주문(Order)'과 '고객(Customer)' 두 개의 엔티티를 가지고 있다고 가정해봅시다.
고객(Customer) 엔티티: id (기본 키) name email
주문(Order) 엔티티: id (기본 키) orderDate customerId (외래 키, Customer의 id를 참조)
Customer newCustomer = new Customer("John Doe", "[email protected]");
Order newOrder = new Order(new Date(), newCustomer);
session.save(newCustomer);
session.save(newOrder);
이 코드에서 우리는 새로운 고객을 생성하고, 그 고객에 대한 새로운 주문을 생성합니다. 만약 Hibernate가 insert 연산을 update 연산보다 먼저 실행하지 않는다면, 다음과 같은 문제가 발생할 수 있습니다:
newOrder를 먼저 저장하려고 시도합니다. 그러나 newOrder는 아직 데이터베이스에 존재하지 않는 newCustomer를 참조하고 있습니다. 이는 외래 키 제약 조건을 위반하게 되어, 데이터베이스 오류가 발생할 것입니다.
하지만 Hibernate의 Action Queue는 이러한 상황을 방지합니다:
먼저 entityInsertions 큐에서 newCustomer를 데이터베이스에 삽입합니다. 그 다음 newOrder를 삽입합니다.
이렇게 함으로써, newOrder가 삽입될 때 이미 newCustomer가 데이터베이스에 존재하므로 외래 키 제약 조건이 위반되지 않습니다. 이는 "참조 무결성"을 유지하는 중요한 메커니즘입니다. 참조 무결성이란 데이터베이스의 관계가 항상 일관성을 유지해야 한다는 규칙을 말합니다. 즉, 자식 테이블(이 경우 Order)의 외래 키는 항상 부모 테이블(이 경우 Customer)의 기본 키를 올바르게 참조해야 합니다. 이러한 방식으로 Hibernate는 개발자가 명시적으로 순서를 관리하지 않아도, 데이터의 일관성과 무결성을 자동으로 유지할 수 있게 해줍니다. 이는 특히 복잡한 관계를 가진 큰 데이터 모델에서 매우 유용합니다.
Execute all SQL (and second-level cache updates) in a special order so that foreign-key constraints cannot be violated:
Inserts, in the order they were performed
Updates
Deletion of collection elements
Insertion of collection elements
Deletes, in the order they were performed
프로젝트 1주차인데 다들 저보다 경험이 많아서 배울 점이 많습니다. 모든 것을 자세히 공부할 시간은 없어서 캠프 끝난 후에 공부할 todo 에 쌓이고 있는데 나중에 한번 정리하면 좋을거 같습니다. 팀원들 믿고 잘 따라가기만 해도 성공일거 같은 프로젝트입니다.