학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 커맨드와 쿼리를 분리한다고 하셨는데, 분산 데이터베이스 환경에서 update 쿼리에서 반환값을 가져오지 않고 다시 findOne을 수행한다고 가정했을때 전파가 아직 이루어지지 않아서 조회가 안되는 경우가 발생할 수도 있을까요? 이전에 물리적으로 분산 데이터베이스 환경에서 update되는 데이터가 많아서 find로 값을 불러오지 못한 경우가 있어서 무조건 update 쿼리를 보낼때 반환값을 받아서 처리했던 기억이 있어서 질문 드립니다.
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
안녕하세요 강의 잘 보고있습니다! 질문이 하나 있는데요 UserResponse 클래스에 보면요 public UserResponse(long id, User user) { this.id = id; this.name = user.getName(); this.age = user.getAge(); } 예전에 만들었던 생성자가 있는데요 public UserResponse(long id, String name, Integer age) { this.id = id; this.name = name; this.age = age; } 이번에 이 생성자를 하나 더 만든 이유가있을까요?
안녕하세요. JPA 강의를 듣고 프로젝트를 진행하던중에 페치조인과 관련된 문제가 생겨서 질문드립니다. 총 4개의 엔티티(A,B,C,D)가 있습니다. B는 각각 A, C와 ManyToOne 관계입니다. * A(1) <- B(N) -> C(1) C는 D와 ManyToOne 관계입니다. * C(N) -> D(1) 이런 상황에서 JPQL로 B를 조회하려합니다. 상세 조건은 아래와 같습니다. B를 조회하면서 C를 페치조인으로 같이 가져오고 싶습니다. (A는 가져오지 않음) 조회 조건은 A의 id 값과 D의 id 값입니다. 위의 조회를 위해서 JPQL을 다음과 같이 짜보았습니다. 1. select b from B b join fetch b.c where b.a.id = :a_Id and b.c.d.id = :d_Id 2. select b from B b join fetch b.c c where b.a.id = :a_Id and c.d.id = :d_Id JPA의 표준 스펙상 페치조인의 대상에는 별칭을 줄 수 없다고 하셔서 별칭을 주지 않고 작성한 것이 1, Hibernate에서 별칭을 허용하기 때문에 별칭을 주고 작성한 것이 2입니다. 그런데 위의 두 JPQL 모두 애플리케이션 로딩시점에서 아예 예외가 터져버리더라구요. SemanticException: query specified join fetching, but the owner of the fetched association was not present in the select list 위에 적어놓은 것과 같이 ManyToOne 관계가 연쇄적으로 걸려있는 상황에서 페치조인을 어떻게 해야하는지 궁금합니다.
안녕하세요.! 아래의 JPQL 반환값 질문 드립니다..! String query = "SELECT m, t FROM MEMBER m JOIN m.team t" List<Object[]> result = em.createQuery(query).getResultList(); for(Object [] row: result){ Member member = (Member)row[0]; Team team = (Team)row[1]; } Object row에는 어떤 값들이 들어가고.. row[0],row[1]에는 어떤 값들이 들어있는지 궁굼합니다.!
안녕하세요.! 강의를 수강하다가 질문 드립니다. Member.class 엔티티가 아래와 같을 때 @Getter @Entity public class Member { @Id private Long id; private String username; private Long age; ... } Query query = em.createQuery("SELECT m.username, m.age from Member m"); List resultList = query.getResultList(); for (Object o : resultList)){ Object[] result = (Object[]) o; //결과가 둘이상이면 Object[]반환 System.out.println("username = " + result[0]); System.out.println("age = " + result[1]); } 와 같은 JPQL문을 짯을 때,, DB에 존재하는 Member 데이터가 id : 1, username : user1, age:10 id : 2, username :user2, age:20 일 경우에, resultList 에는 Obejct[0], Object[1]이 존재하고, 아래 iter문에서 나오는 값은, Object[0][0], Object[0][1] Object[1][0], Object[2][1] 값 인가용? 감사합니다.
<Post> <PostResponse> <PostService> <PostController> <PostControllerTest> org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.data .mapping.PropertyReferenceException: No property 'desc' found for type 'Long'; Traversed path: Post.id 안녕하세요 호돌님 PostControllerTest에서 페이지size와 정렬방법 설정의 "/posts page=1&size=5"은 정상 작동하는데 &sort=id.desc를 작성하면 위와 같은 오류가 발생하는데 뭐가 잘못된건지 모르겠습니다ㅠ
Presentation Layer 테스트 (2) 58:57에 모듈을 분리해도 사실은 서비스 계층에서 BeanValidation을 책임상 하지 않는데 의존하고 있기때문에 의존성을 계속 추가해야 한다. 이렇게 말씀해주셨는데 컨트롤러에서 전부 검증을 책임지지 않고 특수 형태 Validation은 서비스 레이어나 도매인 객체 생성할때 검증한다고 하셨는데 검증 로직을 스프링 AOP,스프링 Assert 로 구현을하면 서비스 계층이 스프링 프레임워크를 많이 의존하게 되는거 같아서요 강사님은 어떤식으로 검증로직을 선호하시고, 선호하시는 이유도 궁금합니다.
좋은 강의 감사드립니다. 덕분에 많은 걸 배워서 마음이 든든해 집니다. 그런데, 하나 궁금한 점이 있어서 여쭤보고 싶습니다. 우리 개발자들은 사실 귀찮은 걸 싫어하기 때문에 기술이 나날이 발전해 가는 것이라 생각이 되는데요, 강사님이 설명주신 부분처럼 Schema나 Payload를 계속해서 수동으로 만드는 것은 개발자 입장에서는 매우 비효율적일거라 생각이 됩니다. 따라서, 이미 저 부분을 해결하기 위한 많은 부분들이 고려되었을 것으로 예상이 되는데요, 혹시 저 부분을 편하게 등록할 수 있는 다른 방법이 있을까요? 키워드라도 주시면 찾아서 공부해 나가는데 큰 도움이 될 것 같습니다. 감사합니다.
//CommunityCommandService.java public void updateCommunity(Long communityId, String description, List<String> newTags) { Community community = communityRepository.findCommunityById(communityId); community.updateCommunity(description, newTags); } 만약, 이런 코드가 있다고 하면 Service는 데이터를 받고 Community 클래스에게 실제 데이터 변경을 위임합니다. //Community.java public void updateCommunity(String description, List<String> tags) { this.description = new Description(description); this.hashtags.updateTags(tags, this); } Service 클래스를 테스트할 때 상태검증으로 테스트한다면, //CommunityCommandService.java @Test void 상태검증_테스트() { community = new Community("dummy Intro", List.of("dummy tag")); given(communityRepository.findById(any)).willReturn(community); communityCommandService.updateCommunity("new intro", List.of("new tag")); assertThat(community.getIntroduce).isEqualTo("new intro"); assertThat(community.getTags).containsExactly("new tag"); } 이렇게 테스트하게 됩니다. 사실 데이터의 변경 자체는 CommunityTest에서 테스트 하였습니다. //CommunityTest.java @Test void updateCommunity() { final Community community = TestCommunity.builder().build(); community.updateCommunity("커뮤니티 소개란 입니다.", List.of("태그1", "태그2")); assertThat(community.getHashtags()).extracting("tag").containsExactly("태그1", "태그2"); assertThat(community.getDescription()).isEqualTo("커뮤니티 소개란 입니다."); } 이렇게 되면 CommunityCommandService에서 내부 Community.updateCommunity를 중복적으로 검증하는게 아닌지 생각이 듭니다. 객체지향 관점에서, Service는 Community에게 위임하여 상태를 변경시킵니다. 실제 내부에 어떠한 변화가 발생했는지에 집중하는게 아니라, 객체에게 위임했는지 여부에 좀 더 초점을 맞춰야하는 걸까요? (verify를 통해서) 질문 저는 사실 상태검증을 더 좋아합니다. 상태검증을 사용한다면 위와 같은 중복검증이 발생하게 되는걸까요? 객체지향의 관점에서 보면 사실 verify를 통해서 호출여부를 판단하는게 더 좋아보입니다. 다만, 상태검증을 위해서라면 위와 같이 중복적으로 검증하는 것을 피할 수 없는건가요? 강사님의 경우, 상태검증을 할 때 위와같이 Community 로직을 다른 곳에서 테스트하였다고 해도, Service에서 다시 테스트하나요?
API하고 TPC부터 스프2탄까지 이제 거의 다 들었습니다~ 사물인터넷 통신은 내 손에 << 강의를 수강하려고 하는데요~ 나온지 기간이 좀 지난터라 진행하는데 있어서 임베디드 관련 아무런 지식이 없는 사람은 관련 프로그램 다운로드가 안된다거나 그런 상황이 생기면 대처가 어려울 거 같아서요 지금 시점에 들어도 강의 따라 진행하는데 문제 없을까요? 사물인터넷 강의도 질문드리면 답변 해주시나요~?
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
안녕하세요, 강사님. loanBook() 서비스 로직 관련 질문입니다. 강의를 듣기 전 혼자 작성해보았는데요, Book book = bookRepository.findByName(request.getBookName()); if(book == null) { throw new IllegalArgumentException("대출할 책이 존재하지 않습니다."); } UserLoanHistory userLoanHistory = userLoanHistoryRepository.findByBookName(book.getName()); if(userLoanHistory.getBookName() == request.getBookName()) { throw new IllegalArgumentException("이미 대출된 책 입니다."); } userLoanHistoryRepository.save(new UserLoanHistory(request.getUserName(), request.getBookName())); 위와 같이 작성해보았습니다. 제가 생각한 로직은 책이 존재하는지 찾고 존재한다면, 책 이름으로 대출 도메인에서 정보 가져와서 대출 정보의 책 이름과 대출하려는 책 이름이 같으면 예외처리를 하고 대출이 가능하면 UserLoanHistory 객체를 저장한다. 입니다. 하지만 userLoanHistoryRepository.findByBookName(book.getName()) 이 부분에서 findByBookName 메소드가 실행되지 않는 것 같습니다.(레포지토리에는 작성해주었습니다.) 그 이유가 UserLoanHistory도메인과 Book도메인이 연결되지 않았기 때문일까요?
안녕하세요! QueryDsl 수업을 잘 듣고, 실제 실무에서 활용을 하다가 조금 안되는 부분이 생겨 문의드리게 되었습니다. BooleanBuilder를 활용해서 동적 조건을 적용하고자 하였고 조건 중 and((AandB) or(CandD)) 라는 조건을 추가하기 위해 코드를 작성하였습니다. 해당 부분은 BooleanBuilder tempBuilder = new BooleanBuilder(); for (SiteStatus status: siteStatus) { if (status.equals(SiteStatus.SERVICE)) { tempBuilder.or(Expressions.predicate(Ops.WRAPPED, (serviceBillInfo.status.ne(BillStatus.DELETE).and(serviceBillInfo.billType.eq(BillType.TRIAL))))); } else if (status.equals(SiteStatus.PAID)) { tempBuilder.or(Expressions.predicate(Ops.WRAPPED, (serviceBillInfo.status.ne(BillStatus.DELETE).and(serviceBillInfo.billType.ne(BillType.TRIAL))))); } else { tempBuilder.or(Expressions.predicate(Ops.WRAPPED, (serviceBillInfo.status.eq(BillStatus.DELETE).or(serviceBillInfo.billType.isNull())))); } } builder.and(tempBuilder); 위와 같은식으로 묶어서 처리하였고 디버깅을 통해서 builder라는 BooleanBuilder에 들어간 값을 String 형태로 보면 ((serviceBillInfo.status != DELETE && serviceBillInfo.billType = TRIAL) || (serviceBillInfo.status != DELETE && serviceBillInfo.billType != TRIAL) || (serviceBillInfo.status = DELETE || serviceBillInfo.billType is null)) 와 같이 제가 원하는 대로 builder 안에 값이 들어 있습니다. 그런데 그 이후에 queryFactory에서 조건문 내부로 들어가면 다음과 같이 쿼리문을 실행하게 됩니다. 해당 부분에 대해서 혹시 해결 방법이 있을까요???
요약 QuerydslRepositorySupport 적용 p6spy 적용 쿼리 로그는 출력이 되고 있지만 native query로 출력되지 않음. 로그 예시 -- 현재 출력되는 로그 포맷 select daOrder.id, daOrder.createDate from DaOrder daOrder -- 원하는 로그 포맷 select d.id, d.create_date from da_order d 로컬에서 네이티브 쿼리가 바로 로그에 보이도록 설정하고 싶은데 테이블명이 아닌 클래스명으로 쿼리가 출력이 되고 있는데요 혹시 어떤 설정을 바꿔야하는지 알 수 있을까요??
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
안녕하세요, 강사님. 항상 좋은 강의 너무 감사드립니다. section3과 section4 32강을 들으면서 질문이 생겨서 글 남기게 되었습니다. 인스턴스화를 new를 사용해서 객체로 만들어준다고 이해하면 될까요? 예를 들어 User.class를 Board.class에서 사용할 때 User user = new User()로 만드는 것이 인스턴스화인지 궁금합니다. 스프링 컨테이너에 대해 맞게 이해한 것인지 궁금합니다. 제가 이해한 바로는 컨테이너는 스프링 빈들을 대신 인스턴스화하고, 빈들끼리의 관계를 자동으로 맺어주고(의존성 자동으로 설정), 생성자를 통해 스프링 빈들끼리 서로 사용이 가능하게 한다는 것입니다. 이해한 개념이 맞는지 궁금합니다. returnBook관련 질문입니다. loanBook의 코드를 최대한 재활용해서 작성해보았는데요, @Transactional public void returnBook(BookReturnRequest request) { Book book = bookRepository.findByName(request.getBookName()); if(book == null) { throw new IllegalArgumentException("대출할 책이 존재하지 않습니다."); } // 유저 찾고 User user = userRepository.findByName(request.getUserName()); if(user == null) { throw new IllegalArgumentException("사용자가 존재하지 않습니다."); } // 이미 대출 중인 책인지 확인하고 if(userLoanHistoryRepository.existsByBookNameAndIsReturn(book.getName(), true)) { throw new IllegalArgumentException("이미 반납된 책입니다."); } // 책 찾고, 반납 UserLoanHistory history = userLoanHistoryRepository.findByBookName(book.getName()); history.returnBook(); } 테스트 결과, 딱히 이상이 없어보입니다. existsByBookNameAndIsReturn(book.getName(), true)를 사용해도 괜찮을까요? 감사합니다!
[벌크성 수정 쿼리] 강의 11:20쯤에 "같은 트랜잭션이면 같은 엔티티 매니저를 불러온다" 라고 강사님이 언급을 하셨습니다. 질문 : 엔티티 매니저는 싱글톤 객체처럼 딱 1개만 가지고 재활용하면서 사용하는 것이 아니라, 트랜잭션이 실행될 때[마다] 새로운 엔티티 매니저가 생성되는 건가요??
오류 난 거 몇 가지 적겠습니다. 이제 User 클래스에 @Table(name = "users") 붙여줘야 합니다. h2 버전 올라가면서 테이블 이름 user를 사용 못 합니다. 9:15에서 실행하면 중간에 에러 떠요. 15:44 sql: init: mode: always 그리고 이전까지 h2가 잘 실행됐는데 이번 편에서 localhost:8080/h2-console 접속 시 whitelabel이 계속 나오고 Application 실행 시에 h2가 실행된다는 메시지도 안 나오는 미친 에러 걸려서 (h2 로그 안 나옴) 해결법을 못찾아서 압축하고 드라이브 올리고 마지막으로 확인차 다운받아서 확인해 봤는데 다시 h2 실행이 잘 되네요..? 왜 그런지 아시는 분 댓글 부탁드립니다 ㅎㅎ
https://www.inflearn.com/questions/284950/querydsl-random-select%EA%B4%80%EB%A0%A8 2년정도 전에 Querydsl에서 ramdom select는 지원하지 않는다고 하셨는데 지금은 찾아보니 Expressions.numberTemplate()을 통해 SQL Function을 사용할 수 있다고 하는데 권장하는 사용법인지, 올바른 random select 방법인지 궁금합니다. 추가로 같은 결과를 반환하는 random select, distinct, limit, 프로젝션을 한번에 수행하는 2개의 방법인데 2개의 차이는 다음과 같고 어느것을 추천하시는지 궁금합니다. case1의 방법이 limit를 가져오기에 불필요한 count쿼리를 추가로 날리지 않지만 실행 시간이 더욱 큽니다. case1 - Querydsl 사용 테스트 실행시간 : 78ms count 쿼리를 추가로 생성하지 않음 public List<QuizWordDto> findMyWordRandomForQuiz() { return queryFactory .select(Projections.constructor(QuizWordDto.class, myWord.name, myWord.morpheme, myWord.mean)) .distinct() .from(myWord) .orderBy(Expressions.numberTemplate(Double.class, "RAND()").asc()) .limit(40) .fetch(); } case2 - 페이징을 이용하여 Limit 가져오기 테스트 실행시간 : 22ms count 쿼리를 추가로 생성 @Query(value = "SELECT DISTINCT new com.ll.kotudy.word.service.dto.QuizWordDto(mw.name, mw.morpheme, mw.mean) " + "FROM MyWord mw " + "ORDER BY FUNCTION('RAND')", nativeQuery = false) Page<QuizWordDto> findDistinctRandomQuizWords(Pageable pageable); 테스트 코드 @BeforeEach void init() { for (int i = 0; i < 50; i++) { myWordRepository.save(new MyWord("동물" + i, "명사", "사람을 제외한 길짐승, 날짐승, 물짐승 따위를 통틀어 이르는 말." + i)); } } @Test void findMyWordForQuiz() { long startTime = System.currentTimeMillis(); PageRequest pageRequest = PageRequest.of(0, 40); Page<QuizWordDto> distinctRandomQuizWords = myWordRepository.findDistinctRandomQuizWords(pageRequest); long endTime = System.currentTimeMillis(); System.out.println(String.format("코드 실행 시간: %20dms", endTime - startTime)); } @Test void findMyWordForQuiz_querydsl() { long startTime = System.currentTimeMillis(); List<QuizWordDto> myWordRandomForQuiz = myWordRepository.findMyWordRandomForQuiz(); long endTime = System.currentTimeMillis(); System.out.println(String.format("코드 실행 시간: %20dms", endTime - startTime)); }