묻고 답해요
131만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
실행 시 시퀸스 자동 생성
질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]여기에 질문 내용을 남겨주세요.단방향 연관관계 강의 9:40에서 이전에 작성했던 시퀸스 모두 삭제하고 다시 작성해서 실행했는데 에러가 떠서 drop SEQUENCE MEMBER_SEQ;로 h2 디비에서 시퀸스를 지우고 다시 실행했습니다. 근데 왜 실행할 때 아래와 같이 각 테이블에 대한 시퀸스가 자동으로(1 increment by 50으로) 생성되는건가요? 강의에서는 1 increment by 1로 생성됩니다.
-
해결됨실전! Querydsl
서브 쿼리기 때문에 이름이 없다고 하신 이유에 대해 질문드립니다.
프로젝션과 결과 반환 - DTO 조회 강의의 15:23에서 '서브쿼리이기 때문에 이름이 없다'고 하신 부분이 이해가 가지 않아서 추가 설명해주시면 감사하겠습니다 🙂
-
해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
주문조회 강제 초기화 질문
@GetMapping("/api/v1/orders") public List<Order> ordersV1() { List<Order> all = orderRepository.findAll(); for (Order order : all) { order.getMember().getName(); //Lazy 강제 초기화 order.getDelivery().getAddress(); //Lazy 강제 초기화 List<OrderItem> orderItems = order.getOrderItems(); orderItems.stream().forEach(o -> o.getItem().getName()); //Lazy 강제 초기화 } return all; }첫 질문Lazy방식이기에 조인되어 있는 필드를 가져오지 못하기에 member와 delivery는 One이기 때문에 get으로 초기화 하고orderItem은 Many이기 때문에 List형식으로 stream으로 초기화 하는걸로 이해해도 될까요?강제 초기화를 하는 이유는 값을 넣어주기 위해..? 인가요..? 두번째 질문orderItems.stream().forEach(o -> o.getItem().getName());이 부분 코드 제가 이해한게 맞는지 확인부탁드립니다.o(orderItems 컬렉션에서 하나하나)에서 getItem().getName()를 가져와서 반환할 것이다.근데 getName(이름 가져오기)만 하는데 Item의 모든 api값을 가져오는것 같아서 질문드립니다.
-
미해결코드로 배우는 React with 스프링부트 API서버
섹션 2 마지막 REST컨트롤러-수정/삭제,CORS 설정 첨부파일을 요청합니다.
안녕하세요 강의를 듣는중에 섹션 2 마지막 REST컨트롤러-수정/삭제,CORS 설정 이 부분에서 PutMapping modify 메서드에 서비스 명과 파라미터명이 위에서 코딩한거랑 다르더라구요 service가 아니라 todoservice이고 파라미터는 todoDTO가 아니라 dto 던데 제가 입력한 부분이 정확히 맞는건지 확인하기가 어려워서 코드를 볼 수 있는 첨부파일을 요청합니다!
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
JPA에서 lombok Builder 사용
JPA에서 lombok의 Builder 어노테이션을 사용해도 문제가 없나요?엔티티 어노테이션을 붙여준 클래스에서도 가능한가 싶어 질문드립니다!
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
gradle vs maven
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]구글 트렌드에서 검색을 했을 때 maven 사용이 gradle보다 현저히 높게 사용된다고 나오는데 gradle을 사용하는 이유가 있을까요?!또한 둘에 대해 검색하면 gradle이 스펙상 좋다고 하는데 왜 gradle이 maven보다 사용이 더 적은건가요??
-
미해결PZM기반 실무중심 백엔드 부트캠프(프리트레이닝)
root-context가 다르게 나와서 복사하려는데 깃허브 어디로 들어가야 하나요?
root-context가 다르게 나와서 복사하려는데 깃허브 어디로 들어가야 하나요?
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
로그에 traceId, spanId 모두 잘 찍히는데 traceId로 조회가 안 됩니다.
로그에 traceId, spanId 모두 잘 찍히는데 브라우저의 zipkin에서 traceId로 조회를 하면 no trace가 뜨네요. 스프링부트 3에 맞춰서 깃허브에 올려주신 자료 참조해서 디펜던시 맞게 설정하고 yml에도 올려주신 자료대로 수정했는데 이런 문제가 생기면 어떤 부분이 잘못된 걸까요?
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
db 컬럼 이름 형식
JPA 관련 질문 드립니다.db 테이블의 컬럼 이름을 만들 때 isSold 라는 컬럼을 케멀케이스 형식으로 만들었습니다.그런데 이러한 함수를 만들어서 사용할려고 하니 계속 에러가 떴습니다.이러한 에러가 나와서 살펴보니 is_sold라는 컬럼을 찾는 것 같은데 저는 IsSold라고 컬럼명을 지어서 오류가 나는 거라고 생각이듭니다.제가 궁금한점은1. jpa가 스네이크케이스 형식으로 컬럼명을 자동으로 찾는 것 같아 오류가 나오는 걸로 생각이 드는데 이게 맞을까요?2. 그럼 db의 컬럼 명을 처음 만들 때 컬럼명이 길 경우 스네이크케이스 형식으로 만들어야 할까요? 보편적으로 어떻게 하는지 궁금합니다.
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
o.s.b.d LoggingFailureAnalysisReporter 오류
2024-05-16T23:53:30.318+09:00 ERROR 11428 --- [library-app] [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter : ***************************APPLICATION FAILED TO START***************************Description:Parameter 0 of constructor in com.group.libraryapp.service.book.BookService required a bean of type 'com.group.libraryapp.domain.book.BookRepository' that could not be found.Action:Consider defining a bean of type 'com.group.libraryapp.domain.book.BookRepository' in your configuration.Process finished with exit code 0이런 오류가 뜨는데 bean 설정도 강의 내용그대로 한거 같은데 계속 코드를 수정하려고 해도 Error 가 떠서 해결방법을 모르겠습니다package com.group.libraryapp.service.book; import com.group.libraryapp.domain.book.Book; import com.group.libraryapp.domain.book.BookRepository; import com.group.libraryapp.domain.user.User; import com.group.libraryapp.domain.user.UserRepository; import com.group.libraryapp.domain.user.loanhistory.UserLoanHistory; import com.group.libraryapp.domain.user.loanhistory.UserLoanHistoryRepository; import com.group.libraryapp.dto.Book.request.BookCreateRequest; import com.group.libraryapp.dto.Book.request.BookLoanRequest; import com.group.libraryapp.dto.Book.request.BookReturnRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class BookService { private final BookRepository bookRepository; private final UserLoanHistoryRepository userLoanHistoryRepository; private final UserRepository userRepository; public BookService( BookRepository bookRepository, UserLoanHistoryRepository userLoanHistoryRepository, UserRepository userRepository) { this.bookRepository = bookRepository; this.userLoanHistoryRepository = userLoanHistoryRepository; this.userRepository = userRepository; } @Transactional public void saveBook(BookCreateRequest request){ bookRepository.save(new Book(request.getName())); } @Transactional public void loanBook(BookLoanRequest request){ Book book = bookRepository.findByName(request.getBookName()) .orElseThrow(IllegalArgumentException::new); if(userLoanHistoryRepository.existsByBookNameAndIsReturn (book.getName(),false)){ throw new IllegalArgumentException("이미 대출되어 있는 책 입니다"); } User user = userRepository.findByName(request.getUsername()) .orElseThrow(IllegalArgumentException::new); userLoanHistoryRepository.save(new UserLoanHistory(user, book.getName())); } @Transactional public void returnBook(BookReturnRequest request){ User user= userRepository.findByName(request.getUserName()) .orElseThrow(IllegalArgumentException::new); UserLoanHistory history = userLoanHistoryRepository.findByUserIdAndBookName(user.getId(), request.getBookName()) .orElseThrow(IllegalArgumentException::new); history.doReturn(); } } package com.group.libraryapp.domain.book; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; public interface BookRepository extends JpaRepository<Book,Long> { Optional<Book> findByName(String bookName); }
-
해결됨스프링 DB 2편 - 데이터 접근 활용 기술
DB강의 듣다 강이ppt의 외래키 부분을 보고 궁금증이 생겨 질문 남깁니다.
웹 개발을 할 때 DDL을 통해 생성되는 테이블들은 모두 서비스에서 사용되는 객체들을 보고 만드는것 같은데 (예를 들면 Member 클래스, Item클레스들을 생각했습니다)만약 어떤 회원 A가 아이템A를 등록하였으면 데이터 베이스의 회원과 아이템 사이에는 등록이라는 관계가 생성이 되고 회원 1명은 아이템을 여러개 등록이 가능하다면 Member 테이블의 PK를 Item 테이블의 FK로 등록되며 Item 테이블의 속성들은 (id, item_name, price, quantity, member_id)로 설정이 될것 같은데 이런 경우 Item 클레스의 멤버변수로Member member_id; 를 생성해주어야 할것 같은데 이런 외래키 값은 도메인을 설계할때 어떻게 처리해야 하나요?그리고 api로 통신할 때 클라이언트 에게 데이터를 넘겨줄 때 스프링 입문 강의에서 hello 객체자체를 return 하면 스프링의 잭슨라이브러리가 json포멧으로 변환해서 넘겨준다고 해주셨는데 여러개의 테이블이 조인된 결과를 json으로 반환 해주려면(예를 들어서 멤버 A가 등록한 아이템의 이름과 가격, 멤버의 이름을 요청한다면 반환되는 튜플이 item_name, price, member_name) 이것들은 하나의 객체가 아닌 Member클래스와 Item클래스의 일부 변수들을 사용한 새로운 값들인데 이럴때는 어떤 방법으로 return해주어야 하나요? 클라이언트측과 조율을 하여 검색되는 조건을 설정하여 조인검색의 제약을 설정하나요? 제약을 설정한다면 반환할 때 (item_name, price, member_name)이 3개의 속성들을 멤버변수로 사용하는 새로운 클래스를 생성하여 반환해 주어야 하나요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
초반 진행 시 오류
Execution failed for task ':JpashopApplication.main()'.> Process 'command 'C:\Program Files\Java\jdk-17\bin\java.exe'' finished with non-zero exit value 1 이런 오류가 계속 나고 있습니다. 최대한 똑같이 따라하고 있다 생각했는데 어디가 잘못된 걸 까요?
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
스크린 샷 문의
안녕하세요 인프런에서 업데이트를 한 것인지 어제까지만 해도 잘 되던 스크린샷 기능이 오늘부터 갑자기 안되네요..ㅜㅜ예전에는 이런 식으로 강의 노트에 스크린샷 기능을 통해서 전체화면 말고 필요한 부분만 캡쳐하고 정리했었는데..혹시 인프런 자체의 일시적인 문제일까요?
-
미해결Practical Testing: 실용적인 테스트 가이드
a 서비스에서 b 서비스를 의존하는 코드에 대한 테스트는 어떻게 해야 되나요??
안녕하세요 강사님, 궁금한게있습니다.인스타그램, 페이스북을 사용할 때 제가 쓴 게시글에 다른 사람이 댓글을 달면 알림이 생성되는데, 제가 작성한 로직에서는 CommentService에서 댓글을 작성하고 alarmService를 호출하여 알림까지 생성하는 로직입니다.이렇게 로직을 짰을 때 제가 생각한 문제점에 대한 해답을 찾고 싶습니다.1. CommentService에서 다른 Service를 의존하게 되는 것2. 댓글 작성이라는 테스트를 짤 때 댓글 작성에 초첨을 맞출 수 없고 알림까지 테스트를 작성해야 되기 떄문에 핵심 기능 외에 다른 부가적인 기능 때문에 테스트의 집중도가 떨어집니다.3. 한 트랙잭션에 묶여서 알림을 생성하는데 문제가 발생하면 댓글도 생성되지 않습니다.이러한 경우 어떤 학습을 통해 개선할 수 있는지 가르쳐주실 수 있나요?
-
미해결스프링 DB 2편 - 데이터 접근 활용 기술
EntityManager 주입 질문드립니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]JpaConfig 안에 있는 EntityManager는 어떻게 주입이 되는 건가요? 제가 대략적으로 생각한 바는 ItemServiceApplication 이 @SpringBootApplication 어노테이션이 붙어있어서 스프링 부트로 작동하게 되고, @Import(JpaConfig.class) 애노테이션을 붙여줌으로써 스프링부트와 JpaConfig가 연동되게 되어서 스프링부트가 JpaConfig에서 쓰이는 EntityManager를 자동으로 주입해주는 것입니다. 제가 생각한 내용이 맞는지 궁금하고요 선생님들의 정확한 설명을 듣고 싶습니다. 감사합니다.
-
미해결스프링 DB 2편 - 데이터 접근 활용 기술
SpringDataJpaConfig 파일 없이 실행 방법 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]SpringDataJpaConfig 파일 없이 @ComponentScan을 사용해서 프로그램을 실행 해보고 싶습니다. 그래서@SprinBootApplication(scanBasePackages="hello.itemservice") 로 스캔 범위 변경 @Import(SpringDataJpaConfig.class) 주석 처리 @Component이 붙은 파일은 자동 빈 등록이 된다고 알고 있습니다. 추가로 처리 해야 할 부분이 있을까요?
-
미해결Practical Testing: 실용적인 테스트 가이드
동시성 이슈 - 3회 이상 재시도를 자동으로 하게 하는 방법
안녕하세요,동시성 이슈에 대한 이야기를 해주시면서 "등록 시도를 했는데 유니크에서 튕겼다면 누군가 먼저 신규 번호를 선점했다는 뜻이니 3회 이상 재시도를 자동으로 하게 하는 방법으로 풀 수 있다"란 말씀을 해주셨습니다.그래서 아래 예시 코드처럼 DataIntegrityViolationException 을 try-catch로 잡아서 재시도를 하라는 뜻으로 이해했습니다. (하지만 로컬에서 동시성 문제를 발생시키는 방법을 찾지 못해 맞는 코드인지 모르겠습니다.. @Transactional이 있다면 DataIntegrityViolationException 를 잡기 위해서 try-catch 블럭 내부에서 flush()를 호출하기 위해 saveAndFlush() 를 사용한다는 말도 있더라구요?)public ExampleEntity save(ExampleEntity entity) { for (int i = 0; i < 3; i++) { try { // 저장 시도 return repository.save(entity); } catch (DataIntegrityViolationException e) { // 유니크 제약 조건 위배 예외 처리 log.info("저장 실패"); } } throw new RuntimeException("저장에 실패했습니다."); }이러한 방법이 맞다면 더 좋은 방법이 있는지, 혹시 만약 이 방법이 아니라면 어떤 방법으로 해결할 수 있는지 알려주시면 감사하겠습니다. 좋은 강의 항상 감사드립니다.
-
해결됨스프링 DB 2편 - 데이터 접근 활용 기술
ResultMap은 굳이 사용 안해도 되는것 아닌가요?
마이바티스 강의 섹션 초반에 application.properties에Mybatis.configuration.map-underscore-to-camel-case=true를 해주었기 때문에 컬럼명 변환을 위한 맵은 해주지 않아도 되는것 아닌가요?추가적인 질문으로 영한님 강의의 로드맵중에 jpa를 집중적으로 강의해주시는 로드맵이 있는데 해당 스프링 로드맵만 수강한 상태에서 개인 프로젝트를 진행할 때 jpa의 지식이 부족할 수 있으니(jpa는 내용이 방대하여 많은 공부가 필요하다고 하셔서) 마이 바티스로 프로젝트를 진행후 jpa로드맵 까지 수강 후 jpa로 프로젝트를 하는게 더 좋은가요?
-
해결됨스프링 DB 2편 - 데이터 접근 활용 기술
빈을 찾을수 없다는 오류가 뜨는데 둘러봐도 빈이 잘 등록된거 같은데 실행이 안됩니다.
이전 질문을 혼자 해결해보다 jdk를 다시 설치하고 적용하니 버전이 다르다는 오류는 해결이 되었는데 이제Description:Parameter 0 of constructor in hello.itemservice.config.MyBatisConfig required a bean of type 'hello.itemservice.repository.mybatis.ItemMapper' that could not be found.Action:Consider defining a bean of type 'hello.itemservice.repository.mybatis.ItemMapper' in your configuration.오류가 발생합니다 둘러보아도 빈 등록은 정상적인거 같은데 이유를 모르겠습니다. H2데이타베이스도 켜주었습니다.https://drive.google.com/file/d/1vIo1htfB2qY7yLUz-JfRT_LDdzO8bAeU/view?usp=drive_link질문글 파일의 드라이브 링크입니다.
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
@OneToMany 지연 로딩 관련하여 질문 드립니다.
[질문 내용]안녕하세요! @OneToMany지연로딩 관련해서 질문 드립니다.아래는 Team, Member 엔티티로, 연관관계를 갖습니다. (1:N) team 엔티티// Team.java package hellojpa; import jakarta.persistence.*; import java.util.ArrayList; import java.util.List; @Entity public class Team { @Id @GeneratedValue @Column(name = "TEAM_ID") private Long id; private String name; @OneToMany(mappedBy = "team", fetch = FetchType.LAZY) private List<Member> members = new ArrayList<>(); public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Member> getMembers() { return members; } public void setMembers(List<Member> members) { this.members = members; } } member.class , 엔티티// Member.java package hellojpa; import jakarta.persistence.*; import javax.xml.namespace.QName; import java.util.Date; @Entity public class Member { @Id @GeneratedValue @Column(name = "MEMBER_ID") private Long id; @Column(name = "USERNAME") private String username; @ManyToOne @JoinColumn(name = "TEAM_ID") private Team team; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Team getTeam() { return team; } public void setTeam(Team team) { this.team = team; } } 위의 team ,member에서는 @OneToMany인데, 아래 코드 작동 시, 프록시 객체들이 조회안되고 진짜 엔티티가 조회되어 지연로딩이 발생 안합니다. package hellojpa; import jakarta.persistence.*; import java.util.List; public class JpaMain { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); EntityManager em = emf.createEntityManager(); //code EntityTransaction tx = em.getTransaction(); tx.begin(); try{ //저장 Team team = new Team(); team.setName("TeamA"); em.persist(team); Member member1 = new Member(); Member member2 = new Member(); member1.setUsername("member1"); member1.setTeam(team); member2.setUsername("member2"); member2.setTeam(team); em.persist(member1); em.persist(member2); em.flush(); em.clear(); Team findTeam = em.find(Team.class, team.getId()); List<Member> members = findTeam.getMembers(); // 이 부분에서 프록시 객체로 조회가 되지 않습니다.! for (Member m : members) { System.out.println(m.getClass()); // member.class로 콘솔 출력 됩니다.. System.out.println(m.getUsername()); } tx.commit(); } catch (Exception e){ tx.rollback(); } finally { em.close(); } emf.close(); } } 아래는 위의 코드 실행 시 콘솔 창입니다. Hibernate: create sequence Member_SEQ start with 1 increment by 50 Hibernate: create sequence Team_SEQ start with 1 increment by 50 Hibernate: create table Member ( MEMBER_ID bigint not null, TEAM_ID bigint, USERNAME varchar(255), primary key (MEMBER_ID) ) 5월 15, 2024 12:26:48 오후 org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@1fbf088b] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode. Hibernate: create table Team ( TEAM_ID bigint not null, name varchar(255), primary key (TEAM_ID) ) Hibernate: alter table if exists Member add constraint FKl7wsny760hjy6x19kqnduasbm foreign key (TEAM_ID) references Team Hibernate: select next value for Team_SEQ Hibernate: select next value for Member_SEQ Hibernate: select next value for Member_SEQ Hibernate: /* insert for hellojpa.Team */insert into Team (name, TEAM_ID) values (?, ?) Hibernate: /* insert for hellojpa.Member */insert into Member (TEAM_ID, USERNAME, MEMBER_ID) values (?, ?, ?) Hibernate: /* insert for hellojpa.Member */insert into Member (TEAM_ID, USERNAME, MEMBER_ID) values (?, ?, ?) ///////////////// ///////////////// ///////////////// Hibernate: select t1_0.TEAM_ID, t1_0.name from Team t1_0 where t1_0.TEAM_ID=? Hibernate: select m1_0.TEAM_ID, m1_0.MEMBER_ID, m1_0.USERNAME from Member m1_0 where m1_0.TEAM_ID=? // 실제 객체 class hellojpa.Member member1 class hellojpa.Member member2 for-each로 member 클래스를 출력했을 때, 프록시 객체로 조회가 되지 않으며, team.getMembers()를 실행할 때 in절로 여러개의 members엔티티를 조회해 오는 것 같습니다.. 제가 강의를 통해 이해한 바로는, @OneToMany는 기본적으로 지연로딩이 걸려 있어, 컬렉션을 조회할 때 각 엔티티들은 '프록시'로 조회되고(지연로딩) , 각 컬렉션의 객체들에 접근할 때 추가적인 (select 문) 조회 쿼리가 발생하여 N+1문제를 낳는다고 알고 있습니다.. -아래는 후반부의 강의 코드 - 강의상 지연이 발생 하는 코드 => OrderItemDto에서 N+1쿼리 발생package jpabook.jpashop.api; import jpabook.jpashop.domain.Address; import jpabook.jpashop.domain.Order; import jpabook.jpashop.domain.OrderItem; import jpabook.jpashop.domain.OrderStatus; import jpabook.jpashop.repository.OrderRepository; import jpabook.jpashop.repository.OrderSearch; import lombok.Data; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; @RestController @RequiredArgsConstructor public class OrderApiController { private final OrderRepository orderRepository; @GetMapping("/api/v1/orders") public List<Order> ordersV1() { List<Order> all = orderRepository.findAllByString(new OrderSearch()); for (Order order : all) { order.getMember().getName(); //Lazy 강제 초기화 order.getDelivery().getAddress(); //Lazy 강제 초기환 List<OrderItem> orderItems = order.getOrderItems(); orderItems.stream().forEach(o -> o.getItem().getName()); //Lazy 강제 } return all; } @GetMapping("/api/v2/orders") public List<OrderDto> ordersV2(){ List<Order> orders = orderRepository.findAllByString(new OrderSearch()); List<OrderDto> collect = orders.stream() .map(o -> new OrderDto(o)) .collect(Collectors.toList()); return collect; } @Data static class OrderDto{ private Long orderId; private String name; private LocalDateTime orderDate; private OrderStatus orderStatus; private Address address; private List<OrdereItemDto> orderItems; public OrderDto(Order o) { orderId = o.getId(); name=o.getMember().getName(); orderDate=o.getOrderDate(); orderStatus=o.getStatus(); address=o.getDelivery().getAddress(); orderItems = o.getOrderItems().stream() .map(orderItem -> new OrdereItemDto(orderItem)) .collect(Collectors.toList()); } } @Getter static class OrdereItemDto{ private String itemName; //상품명 private int orderPrice; //주문 가격 private int count; //주문 수량 public OrdereItemDto(OrderItem orderItem) { itemName=orderItem.getItem().getName(); //문제 상황, 지연로딩 발생 orderPrice=orderItem.getItem().getPrice(); count = orderItem.getCount(); } } } - Order, OrderItems에서도 @OneToMany인데, 지연로딩이 발생하여, orderItems 각각의 필드값을 조회시 N+1쿼리가 나가는 것이 확인되어, 차이점이 무엇인지 알고 싶습니다.@GetMapping("/api/v1/orders") public List<Order> ordersV1() { List<Order> orders = orderRepository.findAllByString(new OrderSearch()); // 지연로딩 데이터 가져오기 for (Order order : orders) { order.getMember().getName(); // 지연로딩 초기화 order.getDelivery().getAddress(); // 지연로딩 초기화 // 2. orderItem -> getClass() for(OrderItem o : orderItems) { System.out.println(o.getClass()) //프록시객체 } //3. 여기서는 select 나가서 진짜 엔티티 갖고 오는거 orderItems.stream().forEach(orderItem -> orderItem.getItem().getName()); // 상품명을 가져오기 위해서 지연로딩 강제 초기화 } return orders; }} 추가질문.. @OneToMany를 걸 경우, 기본 전략이 lazyLoading으로 알고 있습니다..이런 상황에서 getEntityList를 할 때, 프록시 객체가 아니라, 왜 한꺼번에 엔티티를 들고오는지 궁굼합니다..!