실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

(75개의 수강평)

1138명의 수강생
Back-EndJavaSpringSpring BootJPA
월29,333원
88,000원
3개월 할부시
지식공유자 · 김영한
23회 수업· 총 6시간 38분수업
평생 무제한 시청
수료증 발급 강의
수강 난이도 중급이상
MoonHyuck Song 프로필

일대다 조인 관련해서 질문 드립니다 MoonHyuck Song 5일 전
안녕하세요 강의 잘 듣고 있습니다. 일대다 관계 조인에서 현업에서는 어떤 식으로 풀어가시는지 궁금해서 질문드립니다. JPA 기본 강의에서 도메인 설계 시 단방향 맵핑 만으로도 전부 설계 가능하고 필요 시에만 양방향 연관 관계를 설정한다고 하셨는데, 이 필요시가 구체적으로 어떤 경우인지가 궁금합니다. 만약 Order와 OrderItem에서 단방향으로 Order 엔티티에만 @ManyToOne 연관관계를 걸고 설계를 했다는 가정하에 Order와 OrderItem 정보 조회가 필요한 경우, 현업에서는 양방향 연관관계를 맺어서 해결하시는지 아니면 dto를 만들어서 in절 또는 fetch join후 스트림으로 뽑아내시는지 궁금합니다. 양방향 연관관계를 많이 사용하는지도 궁금합니다.

1
kangsy763 프로필

v3 질문드립니다. kangsy763 5일 전
안녕하세요~~ 제가 이해를 잘 못하고 있는 것 같아서 질문드립니다. 이번 강의에서 정리를 하면서, 엔티티 조회와 DTO 직접 조회로 크게 분류하셨는데, 저는 v3를 DTO List를 Return 하니깐 DTO 직접 조회에 속하는데 이 녀석은 batch_fetch_size 의 도움 또한 받는데, 그렇다면 둘 중 어느 곳에 속하는지 아리송 했는데 PDF정리하신 것을 보니 엔티티 쪽이라고 하셨습니다.  1. 여기서 말하는 DTO 직접 조회란, 엔티티의 다른 필요없는 컬럼을 보여주지 않기 위해서 OrderDto의 형태로 리턴해주는 것이 아니라, 따로 패키지를 만들정도의 DTO 를 칭하는 것인가요 ?? 정확한 구분이 어떤 기준으로 나뉘는지가 너무 헷갈립니다. 알 것 같으면서도 눈앞에서 놓치는 듯한 느낌이네요.. 2. 이번 최적화하는 과정에서의 코드에서 stream() 이용법 등 익숙치 않아서 이해하는데 어려움을 많이 느꼈던 것 같습니다. stream().map ~~ 은 괜찮았는데 리스트를 forEach(o->   ~~ 이런식으로 활용하는 부분이요. 혹시 이것과 관련되어서 어떤 키워드로 찾아서 공부를 해야하는지 알고 싶습니다. java8 stream 으로 공부하면 될까요 ?  이번 강의도 굉장히 도움이 많이되고 감사했습니다!!

1
kepha 프로필

batchInsert 가 가능한지 문의드립니다. kepha 6일 전
N+1 문제 해결 방법에 대해서 감명깊게 봤습니다. 내용과는 라른 질문인데요... JPQL(or QueryDSL) 을 이용해서 batchInsert 가 가능한지요.. 문서를 보다 보니까 Hibernate 에서 batchInsert 가 안된다는 이야기가 있어서 문의드립니다.

2
kepha 프로필

@OneToMany 시에 N+1 무제와 페이징 문제 kepha 7일 전
collection 멤버 join 인 경우는 join fetch 를 사용하지 않고 single 멤버 join 인 경우에만 join fetch 를 사용하는건가요? 그럼 collection 멤버 join 쿼리인 경우에는 N+1 이 발생하는데요.  -> 어쨌든 이 경우(OneToMany)에는 native join 쿼리시에도 total rows = r x n 가 되기 때문에 hibernate 에서 1 쿼리로 Collection 멤버까지 받는 방법은 없나 보네요..

3
kepha 프로필

LAZY 로 해놔도 N+1 문제가 계속 발생해서 문의 드립니다. kepha 12일 전
FetchType.LAZY 로 아래와 같이 entity 를 정의하고 아래 JPA 리파지토리를 이용하여 데이타를 가져와서 client(브라우져)에서 받아보면 LAZY 된 child Entity 리스트(quizzList ) 에도 null 이 아니라 리스트로 데이타가 들어가 있습니다. 로그를 보면 N+1 쿼리로 가져와서 보여줍니다. curl -X GET "http://localhost:8080/internal/v1/quest/list2?type=quiz" -H "accept: */*" kotlin SpringBoot 를 사용중인데요.. Jackson data binding 시에 quizzList 속성을 호출해서  그렇게 되는 것인지 궁금합니다. 저는 모든 Entity 조인 컬럼을 LAZY 로 해놔도 N+1 쿼리가 돌면서 전체 결과가 리틴되네요.. lneQuestReposptory.findAllByType(type: String, pageable: Pageable) @Entity(name = "LneQuests")@Table(name = "korbit.lne_quests")@Cacheable@JsonInclude(JsonInclude.Include.NON_NULL)class LneQuest ( var type: String, var title: String, var description: String?, @OneToMany(fetch = FetchType.LAZY, mappedBy = "quest" /* , cascade = [CascadeType.ALL] */) var quizzList: MutableList<LneQuizz> = mutableListOf())

2
개발자 프로필

어플리케이션 실행시 인텔리제이 콘솔에 찍히는 sql statement가 1줄로 나오는 문제! 개발자 15일 전
2020-06-23 17:24:25.174 DEBUG 5276 --- [nio-8080-exec-5] org.hibernate.SQL                        : select order0_.order_id as order_id1_6_0_, member1_.member_id as member_i1_4_1_, delivery2_.delivery_id as delivery1_2_2_, order0_.delivery_id as delivery4_6_0_, order0_.member_id as member_i5_6_0_, order0_.order_date as order_da2_6_0_, order0_.status as status3_6_0_, member1_.city as city2_4_1_, member1_.street as street3_4_1_, member1_.zipcode as zipcode4_4_1_, member1_.name as name5_4_1_, delivery2_.city as city2_2_2_, delivery2_.street as street3_2_2_, delivery2_.zipcode as zipcode4_2_2_, delivery2_.status as status5_2_2_ from orders order0_ inner join member member1_ on order0_.member_id=member1_.member_id inner join delivery delivery2_ on order0_.delivery_id=delivery2_.delivery_id limit ? 2020-06-23 17:24:25.176  INFO 5276 --- [nio-8080-exec-5] p6spy                                    : #1592900665176 | took 0ms | statement | connection 7| url jdbc:h2:tcp://localhost/~/shop select order0_.order_id as order_id1_6_0_, member1_.member_id as member_i1_4_1_, delivery2_.delivery_id as delivery1_2_2_, order0_.delivery_id as delivery4_6_0_, order0_.member_id as member_i5_6_0_, order0_.order_date as order_da2_6_0_, order0_.status as status3_6_0_, member1_.city as city2_4_1_, member1_.street as street3_4_1_, member1_.zipcode as zipcode4_4_1_, member1_.name as name5_4_1_, delivery2_.city as city2_2_2_, delivery2_.street as street3_2_2_, delivery2_.zipcode as zipcode4_2_2_, delivery2_.status as status5_2_2_ from orders order0_ inner join member member1_ on order0_.member_id=member1_.member_id inner join delivery delivery2_ on order0_.delivery_id=delivery2_.delivery_id limit ? select order0_.order_id as order_id1_6_0_, member1_.member_id as member_i1_4_1_, delivery2_.delivery_id as delivery1_2_2_, order0_.delivery_id as delivery4_6_0_, order0_.member_id as member_i5_6_0_, order0_.order_date as order_da2_6_0_, order0_.status as status3_6_0_, member1_.city as city2_4_1_, member1_.street as street3_4_1_, member1_.zipcode as zipcode4_4_1_, member1_.name as name5_4_1_, delivery2_.city as city2_2_2_, delivery2_.street as street3_2_2_, delivery2_.zipcode as zipcode4_2_2_, delivery2_.status as status5_2_2_ from orders order0_ inner join member member1_ on order0_.member_id=member1_.member_id inner join delivery delivery2_ on order0_.delivery_id=delivery2_.delivery_id limit 100; 2020-06-23 17:24:25.177 DEBUG 5276 --- [nio-8080-exec-5] org.hibernate.SQL                        : select orderitems0_.order_id as order_id5_5_1_, orderitems0_.order_item_id as order_it1_5_1_, orderitems0_.order_item_id as order_it1_5_0_, orderitems0_.count as count2_5_0_, orderitems0_.item_id as item_id4_5_0_, orderitems0_.order_id as order_id5_5_0_, orderitems0_.order_price as order_pr3_5_0_ from order_item orderitems0_ where orderitems0_.order_id in (?, ?) 2020-06-23 17:24:25.178  INFO 5276 --- [nio-8080-exec-5] p6spy                                    : #1592900665178 | took 0ms | statement | connection 7| url jdbc:h2:tcp://localhost/~/shop select orderitems0_.order_id as order_id5_5_1_, orderitems0_.order_item_id as order_it1_5_1_, orderitems0_.order_item_id as order_it1_5_0_, orderitems0_.count as count2_5_0_, orderitems0_.item_id as item_id4_5_0_, orderitems0_.order_id as order_id5_5_0_, orderitems0_.order_price as order_pr3_5_0_ from order_item orderitems0_ where orderitems0_.order_id in (?, ?) select orderitems0_.order_id as order_id5_5_1_, orderitems0_.order_item_id as order_it1_5_1_, orderitems0_.order_item_id as order_it1_5_0_, orderitems0_.count as count2_5_0_, orderitems0_.item_id as item_id4_5_0_, orderitems0_.order_id as order_id5_5_0_, orderitems0_.order_price as order_pr3_5_0_ from order_item orderitems0_ where orderitems0_.order_id in (4, 11); 2020-06-23 17:24:25.179 DEBUG 5276 --- [nio-8080-exec-5] org.hibernate.SQL                        : select item0_.item_id as item_id2_3_0_, item0_.name as name3_3_0_, item0_.price as price4_3_0_, item0_.stock_quantity as stock_qu5_3_0_, item0_.author as author6_3_0_, item0_.isbn as isbn7_3_0_, item0_.actor as actor8_3_0_, item0_.director as director9_3_0_, item0_.artist as artist10_3_0_, item0_.etc as etc11_3_0_, item0_.dtype as dtype1_3_0_ from item item0_ where item0_.item_id in (?, ?, ?, ?) 2020-06-23 17:24:25.186  INFO 5276 --- [nio-8080-exec-5] p6spy                                    : #1592900665186 | took 0ms | statement | connection 7| url jdbc:h2:tcp://localhost/~/shop select item0_.item_id as item_id2_3_0_, item0_.name as name3_3_0_, item0_.price as price4_3_0_, item0_.stock_quantity as stock_qu5_3_0_, item0_.author as author6_3_0_, item0_.isbn as isbn7_3_0_, item0_.actor as actor8_3_0_, item0_.director as director9_3_0_, item0_.artist as artist10_3_0_, item0_.etc as etc11_3_0_, item0_.dtype as dtype1_3_0_ from item item0_ where item0_.item_id in (?, ?, ?, ?) select item0_.item_id as item_id2_3_0_, item0_.name as name3_3_0_, item0_.price as price4_3_0_, item0_.stock_quantity as stock_qu5_3_0_, item0_.author as author6_3_0_, item0_.isbn as isbn7_3_0_, item0_.actor as actor8_3_0_, item0_.director as director9_3_0_, item0_.artist as artist10_3_0_, item0_.etc as etc11_3_0_, item0_.dtype as dtype1_3_0_ from item item0_ where item0_.item_id in (2, 3, 9, 10); 위와 같이 콘솔에 찍히는 sql 문이 정열되지 않게 보입니다. 윈도우에 설치된 인텔리제이는 무료버전을 사용하고 있고 설정된 application.yml은 아래와 같습니다. spring: datasource: url: jdbc:h2:tcp://localhost/~/shop username: sa password: driver-class-name: org.h2.Driver jpa: hibernate: ddl-auto: create properties: hibernate:# show-sql: true format-sql: true default_batch_fetch_size: 100logging: level: org.hibernate.SQL: debug# org.hibernate.type: trace 콘솔에 sql문이 정렬되게 하는 방법은 무엇인가요?

3
밥상어 프로필

insert문의 ?로 표시되는 parameter 값 보는 방법 알려주세요~ 밥상어 29일 전
insert into member ~ values (?, ?, ?, ?)로 표시된후 강의영상에는 ?에 들어간 파라미터값이 표시되는데 yml파일에서 설정을 어떻게 하면 볼 수 있나요?

1
조호형 프로필

deleteAllByMemberId 결과확인 문의(삭제가 안됨) 조호형 29일 전
Member, MemberAuth 테이블이 있습니다. Member (1) : MemberAuth (N) 의 관계이고, MemberAuth의 데이터를 삭제하려고 아래와 같이 했는데 실제로 삭제가 되지 않네요. 서비스에서 삭제결과는 제대로 디버깅에서 확인이 되는데요. MemberAuthRepository.java @Repositorypublic interface MemberAuthRepository extends JpaRepository<MemberAuth, Long> { List<MemberAuth> findByMemberId(Long memberId); int deleteAllByMemberId(Long memberId);} MemberService.java : changeRole에서 기존 Role을 삭제하는 부분입니다. @Transactional public void changeRole(MemberDto memberDto, List<MemberAuthDto> memberAuthDtos) throws Exception { Member member = memberRepository.findByEmail(memberDto.getEmail()); if(member==null) { throw new UsernameNotFoundException(memberDto.getEmail()); } //기존 ROLE을 찾아서 모두 지운다. int iDel= memberAuthRepository.deleteAllByMemberId(member.getId()); //ToDo :: 넘어온 ROLE 을 생성한다. } 디버깅으로 보면 iDel 값이 확인이 됩니다. 그런데 데이터베이스 확인하면 값이 지워지지 않고있네요. 어찌해야 하는걸까요? 

6
양동우 프로필

static에 관한 질문이 있습니다. 양동우 1달 전
안녕하세요 강의를 시청하고 있는 학생입니다.  교수님께서 CreateMemberResponse와 CreateMemberRequest 클래스들을 static 으로 만드셨는데 혹시 어떤이유에서 static 선언을 하신건가요??? 항상 유익한 강의를 만들어주셔서 감사합니다

1
Junyoung_Choi 프로필

ManyToMany 관계 동작이 조금 어렵네요.. Junyoung_Choi 1달 전
강의를 들으면서 토이 프로젝트를 진행중에 있습니다! 사용자(Account)가 평소 여러 주제의 태그(Tag) 중 관심 있었던 주제의 태그를 프로필에 등록하는 기능을 구현 중에 있으며, Account 라는 엔티티와 Tag라는 엔티티가 AccountTag 라는 엔티티로 각각 1:N 매핑된 형태로 N:M 관계를 표현했습니다. 태그 생성 기능은 Gist과 같이 작성했는데, 사용자에서 특정 관심 태그를 삭제하는 remove 동작을 어떻게 구현해야 할 지 감이 잘 오지 않습니다.. 정리하자면 Tag는 그대로 보존하되, 연관된 AccountTag만을 삭제하고 싶습니다. 마음 같아선 영속성 전이를 통해 delete 동작 없이 List에서 remove만 해서 처리하고 싶은데 AccountTag 엔티티와 연관된 객체가 2개 이상이니 Cascade.ALL을 사용하기도 좀 그래서 이런 경우엔 보통 어떻게 처리를 하는지 궁금합니다!

5
유동관 프로필

강의 잘 보고 있습니다! 질문이 있습니다. 유동관 1달 전
강의 처음부터 따라가면서 토이프로젝트 하나 만들어보고 있는데요~게시판 CRUD를 간단하게 구현해보고 있는데 delete 문 같은 경우 repository 에서 어떻게 처리해줘야 할지 모르겠어서 질문 드립니다! 아래와 같이 코드 작성 해봤는데 잘 안되어서요 ㅎㅎㅎ 좋은 강의 만들어주셔서 감사합니다! public void deleteById(Long id){ em.createQuery("delete b from Board b where b.id = :id",Board.class) .setParameter("id",id);}

3
와니 프로필

클래스 설계가 먼저일까요? 아니면 데이터 베이스 설계가 먼저일까요? 와니 1달 전
안녕하세요. 6개월차 신입 개발자입니다. 실무에서 php(코드 이그나이터)로 개발을 하다가 스프링부트를 알게되어서 따로 공부하고 연습하고 있는 상황입니다.  매번 서비스를 개발할때에 요구사항을 먼저 받고 데이터베이스 설계를 마친뒤에 코드를 개발하곤 했었습니다. 6개월간 그렇게 개발을 하다보니까 데이터베이스 관점으로 생각하고 개발을 하고있게 되었습니다. 영한님이 준비해주신 요구사항들과 엔티티설계 데이터베이스 관계 설계를 보고 클래스를 만들고 코드를 짜는데 무리는 없지만. 정작 요구하는 사람들은 백지에서 원하는 기능만 설명하고 구현해달라! 이런식으로 나오니까 제 머리가 백지가 되어서 결국 PHP짜던식으로 디비설계 -> 비즈니스로직짜기 -> 비즈니스 로직에 필요한 디비컬럼이 없으면 넣고 -> 비즈니스 로직 짜기 -> 무한반복 -> 리팩토링  이런식으로 갑니다. 너무 비 효율적이라고 생각하게 됩니다. 이번에 jpa기본부터 spring data jpa 4강의를 수강하고 실무환경에서 바로 쓸수있도록 하나의 서비스를 개발해보자! 라는 마음으로 개발을 하고있었습니다만.. 요구사항을 만들고 그에대한 엔티티 설계에서 부터 막히게 되었습니다.  1. 클래스 엔티티 = 데이터 베이스 엔티티 라고 생각하는게 맞을까요? 2.  데이터베이스를 짜고 그에 맞는 클래스 엔티티를 짜는게 맞을까요? 3. 서비스를 만드실려고 요구사항을 받은 시점에서 데이터 베이스 관점에서 설계를 하고 그 위에 엔티티클래스들을 맞게 설계하고 그뒤에 클래스들을 잘게잘게 쪼개는 형식으로 개발을 해야할까요? 4. 아니면 데이터 베이스 정규화를 먼저하고 그뒤에 엔티티클래스를 만들고 개발하는게 맞을까요?  5. 디비설계 -> 비즈니스로직 -> 없는 컬럼 넣기 -> 비즈니스로직  이런 패턴이 잘못되었을까요? 처음부터 요구한 설계에 맞게 완벽한 설계후 개발을 해야할까요?  6. 데이터베이스 , 엔티티클래스 설계에 참고할만한 서적이나 강의영상이 있으시면 추천 부탁드립니다 . 좋은 강의 감사합니다!

1
박진영 프로필

주문 내역출력하기 문의 박진영 1달 전
주문 내역에 orderItems 가 하나만 출력 되어서, 전부 출력되는건 직접해보라고 하셔서 질문을 남깁니다. orderList.html 에서 th:each="item : ${orders}" 안에 orderItems 를 다시 반복하게해서 모든 주문 내역을 출력하고 싶은데, 중첩 반복문을 어떤식으로 해야하는지 몰라서 도움을 받고 싶습니다. 아니면 따로 자바에서 orderItem 을 담는 리스트를 만들어서 보내야하는지 궁금합니다. 

2
강민우 프로필

OSIV와 영속성 컨텍스트 강민우 1달 전
안녕하세요 강의 너무 잘 듣고 있습니다. 강의를 듣던 도중 궁금한 부분이 생겨서 질문드립니다. OSIV: false일때 기본적으로 스프링컨테이너는 트랜잭션 범위의 영속성 컨텍스트를 사용한다고 알고 있는데, (1) 만약 트랜잭션이 없는 메소드에서 영속성 컨텍스트를 주입받으면 해당 영속성 컨텍스트는 어떤 의미를 가지는 걸까요? 예를 들어, 컨트롤러(@Transaction없음)에서 EntityManager를 주입받는다면, 트랜잭션 범위 밖의 영속성 컨텍스트인데, 이 경우는 실제로 영속성 컨텍스트가 없다고 보는건가요? (2)또, 컨트롤러에서 EntityManager를 주입받은 뒤  서비스 메소드(@Transcation 있음)에서 또 EntityManager를 주입받은 경우 두 개의 EntityManager가 동일한 EntityManager로 나오는데(em.getDelegate()로 비교하였습니다), @Transaction이 시작될때 영속성 컨텍스트와 데이터베이스 커넥션이  만들어진다고 알고 있었는데 왜 동일한 영속성 컨텍스트를 사용하는지 궁금합니다 ...  질문이 너무 두서가 없는점 양해 부탁드립니다 ...

1
빈센트 프로필

findOne() -> findById() 빈센트 1달 전
안녕하세요. findById().get() 으로 처리하셨는데 실무에서도 이렇게 처리하면 되나요? getors를 쓴다고 하셨는데 이건 무엇인가요?

1
지식공유자 되기
많은 사람들에게 배움의 기회를 주고,
경제적 보상을 받아보세요.
지식공유참여
기업 교육을 위한 인프런
“인프런 비즈니스” 를 통해 모든 팀원이 인프런의 강의들을
자유롭게 학습하는 환경을 제공하세요.
인프런 비즈니스