안녕하세요! 영한님! 강의는 너무나 잘들었습니다!👍👍 강의를 듣고 나서 본격적으로 JPA를 이용한 개발을 진행하려 하는데, 실무에서 적용 시 궁금한 점이 있어서 질문을 남기게 되었습니다. 강의 내용에서 Page 를 활용해서 DB 데이터의 페이징 처리를 할 수 있다는 점에 대해 알려주셔서 굉장히 유용한 방식이라 생각이 듭니다. 이를 실무에서 실제로 적용하기 앞서 고민이 되는 부분은, 페이징이나 정렬과 관련하여 쿼리문을 이용해 처리 를 하는 것과 전제 데이터를 가져와 비즈니스 로직에서 처리 하는 방식 중 어떤 것이 효율 적인지 고민이 되고 검색도 해봤는데 의견이 다 나뉘더라구요. 그래서 영한님께서는 보통 어떤 것을 기준으로 두 가지 방식 중에 선택을 하여 적용을 하시는지 의견을 듣고 싶어서 질문 드리게 되었습니다. 감사합니다!!
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예 [질문 내용] 강사님 강의 정말 잘 보고 있다가 의문점이 생겨 이렇게 질문 남깁니다. 일단 간단하게 예시를 만들면 양방향 관계로 묶인 Member와 Team이 있을때 Team을 삭제할때 해당 Team에 있던 Member도 전부 삭제를 원하는 상황입니다. 데이터는 Team 2개 Team 하나당 3개의 Member씩이 있는 상태입니다. Member.java package com.example.demo.entity; import lombok.*; import javax.persistence.*; @Entity @Table(name = "member") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor public class Member { @Id @Column(name = "member_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long memberId; @Column(name = "member_name") private String name; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "team") private Team team; public Member(String name, Team team) { this.name = name; this.team = team; } } Team.java package com.example.demo.entity; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity @Getter @Setter @AllArgsConstructor @NoArgsConstructor @Table(name = "team") public class Team { @Id @Column(name = "team_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @OneToMany(mappedBy = "team", cascade = CascadeType.ALL, orphanRemoval = true) List<Member> members = new ArrayList<>(); } controller.java package com.example.demo.entity.controller; import com.example.demo.entity.repository.TeamRepository; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor public class Controller { private final TeamRepository teamRepository; @DeleteMapping("/") public void deleteTeam(@RequestParam Long id) { teamRepository.deleteById(id); //deleteById는 JpaRepository에서 제공하는 기본 } } 위의 코드를 실행하고 delete요청을 했을때 Hibernate: select team0_.team_id as team_id1_1_0_ from team team0_ where team0_.team_id=? Hibernate: select members0_.team as team3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.member_name as member_n2_0_1_, members0_.team as team3_0_1_ from member members0_ where members0_.team=? Hibernate: delete from member where member_id=? Hibernate: delete from member where member_id=? Hibernate: delete from member where member_id=? Hibernate: delete from team where team_id=? 이렇게 나오고 Team의 members의 fetch type을 eager로 바꾸었을때는 select team0_.team_id as team_id1_1_0_, members1_.team as team3_0_1_, members1_.member_id as member_i1_0_1_, members1_.member_id as member_i1_0_2_, members1_.member_name as member_n2_0_2_, members1_.team as team3_0_2_ from team team0_ left outer join member members1_ on team0_.team_id=members1_.team where team0_.team_id=? Hibernate: delete from member where member_id=? Hibernate: delete from member where member_id=? Hibernate: delete from member where member_id=? Hibernate: delete from team where team_id=? 이러한 쿼리가 발생하는것을 볼 수 있습니다. 여기서 제가 든 궁금점은 (편의상 맨 위의 쿼리를 1번쿼리라 하겠습니다) 지연로딩을 할때 Team의 Member는 프록시이므로 member select 하긴 할텐데 select members0_.team as team3_0_0_, members0_.member_id as member_i1_0_0_, members0_.member_id as member_i1_0_1_, members0_.member_name as member_n2_0_1_, members0_.team as team3_0_1_ 이 쿼리(2번 쿼리)가 어떻게 나오게 된건지 이해가 되질 않습니다. 최대한 쿼리를 최적화 해보려 했지만 지연로딩을 할때 fetch join, entity graph등을 사용할 수 없어 1번과 2번 쿼리를 즉시로딩을 사용할때 처럼 최적화 할 수가 없었고 delete문도 멤버를 한번에 delete, 그다음 team delete 이렇게 두번으로 최적화 하고 싶었는데 방법이 떠오르질 않습니다. 정확하게 알려주시기 번거로우시면 키워드나 따로 어떻게 공부하면 해결 할 수 있을지 알려주시면 정말 감사드리겠습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예 [질문 내용] h2로 웹사이트 들어가려는데 오류가 떠요 ㅠㅠ 왜이런거죠?
3분만에 1000명 DB 확보하는 DB 추출기 프로그램 개발 강의 (셀레니움 + pyqt + gui + exe 프로그램)
[6512:12744:0216/164613.471:ERROR:device_event_log_impl.cc(218)] [16:46:13.471] USB: usb_device_handle_win.cc:1046 Failed to read descriptor from node connection: 시스템에 부착된 장치가 작동하지 않습니다. (0x1F) 뭐 크롬드라이버 버전 때문이라는데 그래서 import time from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.chrome.service import Service from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC chrome_options = webdriver.ChromeOptions() driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options) import pyperclip 자동 업데이트로 변경하였는데도 오류뜨네요
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 엔티티 클래스 개발 1 강의에서 1:10분 쯤 Member, MemberRepository 를 삭제 후 회원 레포지토리 개발 강의에서 MemberRepository 를 새로 개발하셨습니다. 이때 MemberRepositoryTest 에는 그 전에 작성한 MemberRepository 기준으로 되어 있어 리턴 값이나 필드 값이 (UserName > name) 맞지 않아 오류가 발생하고 있습니다. 그런데, 강사님은 MemberRepository 를 새로 작성할 때 오류가 뜨지 않고 관련해서 언급을 하신 것이 없는 것(돌려봤는데 찾지 못한 것일 수도 있습니다.)으로 간주되는데 MemberRepositoryTest 를 어떻게 처리하신 것인지 궁금합니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] https://drive.google.com/file/d/1nMMxLmSaPSEIpUd17iJ9VjbdbC_Elybx/view?usp=sharing null point Exception이 일어나는데 어디서 문제가 있는지 도저히 못 찾겠습니다.. jap로 올렸습니다ㅜ
안녕하세요. 강의의 미흡한점이 있어 문의드립니다. ● 2-4 강의에서 사이트 링크를 남겨 주신다고 했는데 없네요. ● 1-5 에서 마지막 강의에서 undetected_chromedriver 사용법을 알려 주신다고 했는데 마지막강의에서는 이내용 없습니다. ● 3-1 강의에서도 undetected_chromedriver를 사용해서 코드작성을 A To Z 를 한다고 했는데 없 네요. ● 1-5 강의 들어보고 결정하려 고했는데 마지막에 사용방법 알려준다고 해서 마지막까지 들었는 데 없어서 난감합니다. ● 1-5 에서 undetected_chromedriver 에대한 강의 였는데 이후 강의에서는options.add_argument("--disable-blink-features=AutomationControlled")를 사용하던데 햇갈려서 순서가 맞는지 궁금합니다. 그리고 강사님께 직접 여쭤보고 싶은데 어디에 질문해야 할까요? 답변부탁드립니다.
안녕하세요 강의 보고면서 따라하는 중인데 막히는 부분이 있어서 질문 드립니다. 인스타그램 웹에서 접속하여 필요한 데이터 URL 수집 후 모바일 인스탁램 으로 넘어가는 과정에서 수집한 해당 URL로 인스타그램 앱이 실행되면서 좋아요, 댓글, 팔로우 등과 같은 작업을 해야하는데 저는 여전히 크롬 이든, 인터넷 이든 여전히 해당 데이터URL 웹 페이지가 열리는 오류가 발생하는 중입니다. 강의 중간에서도 모바일로 넘어오는 과정에서 크롬, 인터넷, 인스타그램 뭘로 실행할 건지 물으면 인스타그램 체크하고 "항상" 클릭하면 된다고 하는데 그렇게 설정하려면 어떻게 해야하나요? 저는 인스타그램은 없고 크롬이냐, 인터넷 이냐, 네이버 냐 이렇게 3가지만 뜹니다..ㅠㅜ
안녕하세요! 영한님 강의 질 좋은 강의 너무 감사하게 보고 배우고 있습니다! 다름이 아니라, 엔터티 설계시 주의점 강의에서 setter를 사용하지 않기위해서 엔터티 설정을 아래와 같이 코드 수정을 해보았는데 이렇게 하는 게 더 안전한 방법인가요?? 실무에서도 이렇게 사용하는지 매우 궁금합니다..! Order 엔터티 public class Order{ ... public void addOrderItem(OrderItem orderItem){ orderItems.add(orderItem); // orderItem.setOrder(this); OrderItem.builder() .order(this) .build(); } public void setDelivery(Delivery delivery){ this.delivery = delivery; // delivery.setOrder(this); Delivery.builder() .order(this) .build(); } } OrderItem 엔터티 ... @NoArgsConstructor public class OrderItem { ... @Builder public OrderItem(Order order){ this.order = order; } }
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] @JoinColumn(name="parent_id") 의 parent_id 는 어디서의 column을 의미하는건가요?? @Column(name="parent_id") 부분이 없는거 같은데 어디서 parent_id의 컬럼이 만들어져서 이것과 join을 하는건지 궁금합니다.
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 안녕하세요 Member 객체에 대하여 질문 있습니다. 테스트 코드의 경우 Member member = new Member(); 이런식으로 Member 인스턴스를 생성해서 member.setName("spring"); 이런식으로 쓰이는건 이해가 되는데요 Member 클래스 에서나 MemoryMemberRepository 에서나 따로 member라는 참조변수로 Member()라는 인스턴스(Member member = new Member();와 같은것들)를 생성하지 않았는데 바로 아랫줄에서 member.setId(++sequence);가 쓰일수 있는건지 궁금합니다.
안녕하세요 강의 잘듣고있습니다. 주문서비스에서 cancel이 발생하면 위 Order 엔티티에서 delivery 객체 배송상태 검증 부분이 있는데 Order 와 Delivery 연관관계 매핑시 FetchType.LAZY로 설정되어있으니 잘못검증되는건 아닌가요? jpql로 fetch join으로 가져와야 하는 케이스아닌가해서요
안녕하세요! querydsl 강의를 보고 실무에 적용 하던 중 중첩 객체에 대해서 한번의 join query로 만들 수 없을지 궁금하여 질문 드립니다. 만약, A -< B -< C (-< 은 one to many 를 의미) 관계를 가진 객체가 있다고 할 때 selectFrom(A) .leftJoin(A.B) .leftJoin(A.B.C) .where(A.id.eq(1)) .fetch(); 위 코드의 반환 값이 아래와 같기를 희망 하는데요 A = { id: 1, Bs: [ { id : 1, Cs : [ { id: 1 } ] } ] } oneToMany를 조인 하게 되면, SQL은 many의 row를 반환하게 되면서, A객체가 B의 갯수만큼 반환 되게 됩니다. group by등을 통해 해결 하려 했을 때는, oneToMany 컬렉션들이 모두 불러와지지 않는것을 확인 하였고, group by를 활용 하지 않고, 모든 row를 불러와서 aggregate하는 방식으로 코드를 구현 했습니다. 매번 쿼리문을 작성할 때 마다 aggregate하는 코드를 작성하는 것은 옳지 않을 것 같아, 혹시 더 나은 방법이 있을지 문의 드립니다. 혹시 중첩 쿼리를 join 으로 모두 찾아 객체에서 맵핑하려는 시도가 bad practice라면 쿼리 숫자가 늘어나더라도, findByAId, findByBId 등의 방식으로 여러번 쿼리를 하고, 중간에 캐시 레이어를 두는것이 더 나을지도 궁금 합니다. 항상 좋은 강의 감사합니다 :)