Skip to content

Conversation

@isuh88
Copy link

@isuh88 isuh88 commented Oct 1, 2023

  1. JPQL을 통해 쿼리를 줄이면서 생각해본 것이, fetch join을 통해서 네트워크 통신 비용을 절감할 수 있다고 강의에서 말씀해 주신 것 같은데 스프링 테스트를 통해서 네트워크 통신 비용과 메모리 접근 비용을 비교해볼 수 있나요? 무작정 모든 메서드를 JPQL로 덮어씌우는 게 좋을 것 같지는 않아서요...!
  2. 엔티티 양방향 매핑을 구현할 때 이해의 편의 상 OneToMany와 ManyToOne로만 코드를 작성하였는데 이 경우 ManyToMany와 비교해서 어떠한 장단점이 있나요?
  3. service 내에서 여러 DTO를 사용하는데 프로젝트 구조에 익숙해지기 이전까지는 여러 엔티티, 리포지토리들과 함께 매우 헷갈리더라구요,,, 혹시 이러한 구조에서 얻을 수 있는 장점이 있을까요? 대략 구글링으로 찾아보기는 했는데 잘 정리가 안되는것 같아서요!

추가과제는 시간 나는 대로 구현해 보겠습니다...!

@PFCJeong
Copy link
Member

PFCJeong commented Oct 1, 2023

수혁님 안녕하세요~ 실패하는 테스트가 있습니다.PlaylistIntegrationTest@Transactional를 붙이고 다시 푸시 부탁드립니다.

@isuh88
Copy link
Author

isuh88 commented Oct 2, 2023

수정해서 다시 푸시했습니다!

Copy link
Member

@PFCJeong PFCJeong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿굿~ 과제 잘해주셨네요. 수고하셨습니다.

(1)
FETCH JOIN으로 DB 네트워크 통신을 절감하는 것과 메모리와는 관계가 없습니다. 아마 엔티티 캐싱과 섞인? 질문 같습니다.

DB 통신에 일반적으로 수십~수백 밀리세컨드가 걸리는데요. 어떤 쿼리냐에 따라 더 걸릴 수도 있습니다.

JPQL이 아무래도 쿼리를 직접 짜야하다보니, 어느 정도 성능에 절충이 가능한 상황이라면 굳이 안써도 됩니다. 상황에 맞게 판단하면 될 것 같습니다.

별개로 메모리 접근 비용(엔티티 캐싱)은 음.. 마이크로세컨드 단위 정도로 나왔던 것 같습니다.

(2)
ManyToMany는 직접 코드로 보이는게 아니라, 예상치 못한 쿼리가 날라갈 수 있기 때문에 주의해야 합니다.

다대다 관계에서 단순히 테이블들을 연결만 해주면 되는 경우도 있지만 부가 정보가 필요한 경우도 있습니다.

이 때 결국 OneToMany, ManyToOne을 사용해야합니다.(ManyToMany는 칼럼으로 외래키만 가질 수 있음)

(3)
클라이언트에서 필요로하는 정보의 단위가 꼭 엔티티로 떨어지는 것은 아닙니다. 클라이언트가 필요로 하는 응답은 application layer에 정의되어있을 텐데요. 결국 데이터 변환은 필요합니다.

저희는 단일 모듈로 웹 어플리케이션 서버를 개발하고 있는데요. 개발해야하는 앱이 서버만 있는 것은 아닙니다.

주기적으로 데이터를 처리하는 배치앱을 만들 때도 있는데요. 이 때 레이어를 구분해서 모듈로 나눠두면, 배치앱과 서버앱이 적절히 필요한 모듈을 공유하는 구조를 짤 수 있습니다.

@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
val id: Long = 0L,
@Column(unique = true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

TODO()
val playlist = playlistService.get(id)

var isLiked = false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var 사용은 지양하는 편이 좋습니다

throw PlaylistNeverLikedException()
} else {
playlistLikeService.delete(playlistId = id, userId = user.id)
return ResponseEntity.status(204).build()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

) {
TODO()
) : ResponseEntity<Unit>{
if (playlistLikeService.exists(playlistId = id, userId = user.id)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요 로직은 서비스 안에 들어가는 것이 더 좋을 것 같습니다.


@Query("SELECT pg FROM playlist_groups AS pg LEFT JOIN FETCH pg.playlists")
fun findAllOpenGroups(): List<PlaylistGroupsEntity>
@Query("SELECT p FROM playlists AS p " +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

딱 필요한 테이블까지만 조인해도 좋을 것 같습니다.

throw UserNotFoundException()
}

if (playlistLikesRepository.findByPlaylistIdAndUserId(playlistId, userId) != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exists 함수를 재사용해도 좋을 것 같습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants