묻고 답해요
158만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
DAO와 REPOSITORY의 차이점...
안녕하세요 항상 좋은 강의 제공해주셔서 감사드립니다. 강의를 듣다보니 dao와 repository의 차이점이 궁금해서 질문을 남깁니다. 검색해보니 dao는 data persistence의 추상화 , repository는 collection of objects의 추상화라고 하는데, 사실상 둘의 기능은 비슷하다고 생각합니다. 하지만 둘의 차이를 명확하게 알고 싶어 질문드립니다. 혹시 mybatis를 사용할때 sql과 매핑할때 dao를 사용하고, repository는 엔티티를 영속성 컨텍스트에 영속화 시킬때 사용하는건가요???
-
미해결실전! Querydsl
쿼리 dsl, jpa 사용 케이스
간단한 쿼리도 Querydsl로 작성 시,미연에 에러를 방지할 수 있고, 생산성이 좋다는 강점을 가지고 있는데, 그렇다면 대부분을 쿼리 dsl로 작성하고 몇몇 케이스에서만 jpa로 작성하면 될까요?
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
JPQL 조회 테스트가 올바르게 작성되었나요?
CompStdRepository.java /** * ID로 조회 */public CompStd findOne(Long id) { return em.find(CompStd.class, id);}/** * API ID로 조회 */public CompStd findOneByApiId(String apiId) { String query = "select c From CompStd c where c.apiId = :apiId"; return em.createQuery(query, CompStd.class) .setParameter("apiId", apiId) .getSingleResult();} CompStdService.java /** * ID로 조회 */public CompStd findOne(Long id) { return compStdRepository.findOne(id);}/** * API ID로 조회 */public CompStd findOneByApiId(String apiId) { return compStdRepository.findOneByApiId(apiId);} CompStdServiceTest.java @Testvoid API_ID로_조회() { //given Long createdId = compStdService.insert(getCompStd()); CompStd insertedCompStd = compStdRepository.findOne(createdId); //when CompStd findCompStd = compStdRepository.findOneByApiId(insertedCompStd.getApiId()); //then assertEquals(insertedCompStd, findCompStd);} 1. 다음과 같이 테스트를 작성하였는데 이게 JPQL 조회 기능을 테스트하는 코드로서 올바르게 작성된 건지 궁금합니다. 2. 테스트에서 em.find()로 조회한 객체와 JPQL을 통하여 조회한 객체가 같은 이유는 em.find()로 조회하여 영속성 컨텍스트에 저장된 객체를 JPQL로 조회할 때 객체의 기본 키로 확인하여 같은 객체를 가져오기 때문이라고 보면 될까요?
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
v1: 엔티티직접노출 방식에 달린 주석 질문
@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;} 첨부된 소스코드를 보면 "트랜잭션 안에서 지연 로딩 필요"라고 v1 메소드에 설명이 있습니다. orderRepository.findAll( ); 의 호출이후 트랜잭션은 종료됐을 텐데 그 이후에 강제 Lazy로딩을 하는 것이 위 주석의 설명과 혼동이 됩니다. 기본편에서 진행을 할 때는 항상 tx.commit( ) 이전에 Lazy로딩을 했기 때문에 트랜잭션 안에서 지연로딩을 한다는 의미를 당연하게 받아드렸지만 웹MVC를 결합하면서 Controller쪽에서 findAll() 호출 후 진행되는 상황은 트랜잭션이 종료된 후이기 때문입니다. 답변부탁드립니다. 감사합니다.
-
해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
return new CreateMemberResponse(id); 필요성
@RestController @RequiredArgsConstructor public class MemberApiController { .. @PostMapping("/api/v1/members") public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member) { Long id = memberService.join(member); return new CreateMemberResponse(id); } @Data static class CreateMemberResponse { private Long id; public CreateMemberResponse(Long id) { this.id = id; } } 일 때, memberService.join(member); 의 반환 값이 엔티티가 아니고 단순히 Long id인 값인데도 return id; 로 안하고 CreateMemberResponse 클래스를 만들어 return new CreateMemberResponse(id); 로 하는 이유는 뭔가요 ? 처음에는 Long id = memberService.join(member); return id; 로 했다가 누군가가 inline으로 합쳐버려서 return memberService.join(member); 으로 만들어 버리면 memberService.join의 반환 값이 수정될 때 컴파일이 안뜨고, api에서 스펙이 바뀌어 오류가 생길 가능성이 있어서 컴파일 단계에서 막아버릴려고 CreateMemberResponse 클래스를 만들어 return new CreateMemberResponse(id); 를 해주는 것일까 생각도 들었는데, inline으로 합쳐버리고 memberService.join의 반환값이 바뀌어도 어차피 @PostMapping("/api/v1/members") public Long saveMemberV1(@RequestBody @Valid Member member) { Long id = memberService.join(member); return id; } 인 상태에서 inline하는 거니까 public Long saveMemberV1(..) {..} 에서 return값이 Long타입이 아니게 바뀌면 컴파일 뜰 것 같아서 그것도 아닌가 싶기도 하고 .. 유지보수할 때, 추적하기 쉬우려고 그러는 건가 싶기도 하고 .. 갑자기 든 생각인데, 일반적으로는 단순히 id만 반환할 일이 없으니 일반적인 케이스를 생각해 만드신 건가 싶기도 하고.. 이 케이스만 예외적으로 Long으로 써도 가능한 건지 궁금합니다 :]
-
미해결실전! Querydsl
빌드파일 안에 레포지토리
레포지토리를 왜 빌드파일에 생성하는 건가요?
-
미해결실전! 스프링 데이터 JPA
DTO로 조회시 DTO의 조회 위치는 어디가 되면 좋을까요..?
안녕하세요 강의를 보던 도중 의문이 생겨서 질문남깁니다. Layerd Architecture 에서 Controller, Service, Repository로 역할을 구분해서 레이어당 커플링을 줄이도록 하고 있는 알고 있습니다. 그런데 DTO 의 사용위치 (해당 DTO는 사용자 API)에 대해 궁금한 점이 있습니다. JPA에서 DTO로 조회하면 편하게 데이터를 가져 올수 있는데 해당 DTO가 서비스 혹은 Application Layer에 커플링이 생기는데 이럴 경우는 어떻게 해결해야 될까요..? DTO 자체를 Service DTO, 와 Controller DTO로 분리하여 컨버팅을 해주어야 되는지 아니면 Controller 에서 Repository 를 직접 사용해도 되는 예외상황을 고려해야될지가 고민입니다. 아니면 엔티티를 조회한후 필요한 부분만 DTO로 변환을 하는지 그것도 아니면 Object 객체로 조회한후 Object 안에서 데이터를 추출하는지 어떤 방법을 사용하시는지가 궁금합니다. 보통 이런 경우에는 어떻게 처리하는게 효율적인 방법일까요..? 시스템 개발을 하다가 서비스로 커리어 전환을 하고 있는데 김영한님 강의가 너무 재밌어서 계속 찾아보게 되네요 ㅎ
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
종속성 순환에러 질문드립니다....
선생님 안녕하세요! 꾸준히 걸어가고있는 코린입니다.. 혹시 @Component@Transactional@RequiredArgsConstructorstatic class InitService { 이 부분에서 static이 아닌 private으로 봐꿔보면 종속성 순환에러에 걸리는데 static일때는 메모리를 공유하고 private일때는 공유 하지않아서 생기는 문제인가요?
-
해결됨스프링과 JPA 기반 웹 애플리케이션 개발
프로필 수정 처리와 그 외 개인적인 질문드립니다.
안녕하세요, 먼저 좋은 강의 만들어주셔서 감사드립니다. 해당 강의 '프로필 수정 처리' 학습을 진행하던 중 궁금한 사항이 생겨 질문드립니다. 먼저 강의 내용에서 처럼 POST 방식으로 프로필 수정 요청을 하는 경우 @PostMapping("{URL}") 어노테이션이 설정된 메소드가 실행이 되면서 DB의 정보와 Account 객체가 업데이트 되고, 여기서 Account 객체는 세션에 담긴 객체이지만 '준영속성(detached)' 상태로 AccountService.updateProfile(Account accoutn, Profile profile) 메소드를 통해 Merge를 하는 과정을 확인할 수 있었습니다. 다만, 여기서 궁금한 점은 1. 프로필이 수정되기 전 세션에 설정된 Account 객체는 로그인을 통해 SecurityContext에 저장된 User(Principal, 인증된 사용자 정보)와 동일하겠지만, 프로필 수정 후에는 세션의 Account 객체와 User는 서로 다른 상태가 되는게 맞을까요? 만약, 그렇다면 프로필 수정 후 User 정보도 Account 정보와 동일하게 맞추려면 어떤 방법이 있는지 궁금합니다. 2. [개인적인 질문] 만약, 관리자 페이지가 존재해서 사용자가 애플리케이션을 이용하고 있는 중에 관리자가 회원의 정보를 변경하는 경우 사용자는 자신의 정보가 변경이 되었는지 알 수 있는 방법이 있을까요? - 사용자 측면에서 세션의 Account는 계속해서 관리자가 수정하기 전의 자신의 정보만을 바라보고 있을 것 같다라는 생각이 들어서 질문을 남겨봅니다. 글이 길어 졌네요. 답변 미리 감사드립니다.
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
멤버 이름 중복 익셉션
회원가입시 멤버 이름 중복으로 가입하면 IllegalStateException 창이 발생하는데 이때 Spring MVC 2편에서 배웠던 예외처리 방법을 통해 다시 홈이나 가입화면으로 넘겨주면 되는건가요? 실무에서는 보통 ID중복확인 같은 버튼을 만들어서 검증된 ID만 회원가입이 되게 하는데 , 그 부분은 백엔드개발자가 신경쓸 부분은 아니고 지금처럼 익셉션을 날리면 되는건지 궁급합니다
-
미해결실전! Querydsl
상속 구조에서 querydsl 조회하기
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://docs.google.com/document/d/1j0jcJ9EoXMGzwAA2H0b9TOvRtpwlxI5Dtn3sRtuXQas/edit#heading=h.w2tomwsznga7)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://docs.google.com/document/d/1xCQKit-1V6l6ObeCe49St33RHPzLF_P_c3o7aSDTKs0/edit#heading=h.7dhnp46ven0v)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]여기에 질문 내용을 남겨주세요. 이전 강의 에서 Entity에서 Iteam을 Book , Movie, Ablum으로 상속하는 구조를 가지고 있습니다. 이럴 경우 querydsl로 조회 할 때 dtype을 where 절에서 사용할 수 있는지 궁금합니다. 만약 사용할 수 없다면 실무에 적용할 수 있는 다른 좋은 방법이 있는지 궁금합니다.
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
선생님. Postman에서 Socket hang up 에러가 납니다.
안녕하세요. 선생님! 회원가입, 로그인은 잘 되는데, AuthenticationHeaderFilter를 적용하고 127.0.0.1:8000/user-service/welcome 으로 get 호출하면 NoClassDefFoundError가 발생합니다. filter 코드도 github에 있는 거 그대로이고, application.yml에도 filter로 등록했는데 postman에서 응답을 받을 수 없다면서 Socket hang up 에러가 납니다. 그런데 get으로 저의ip:port/welcome 으로는 조회가 잘 되요..! 제가 h2를 선생님이 설정한 방식이 아닌 tcp 통신으로 진행하고 있었습니다. 이게 문제인 걸까요..? h2를 tcp로 연결 : (jdbc:h2:tcp://localhost/~/user-service)
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
Member테이블과 조인을 하는 이유가 궁금합니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용] Order를 select할 때, 굳이 Member테이블과 조인하는 이유가 궁금합니다. 조인을 하지 않더라도, order를 조회할때, member 테이블로 따로 select문을 써서 값을 가져오고, 만약 fetchType을 LAZY로 할경우 필요할 때 Join쿼리를 추가적으로 날리는 것으로 알고 있습니다. 제가 생각했을 때는, 유일한 예외경우가 "Member가 null값인 Order가 조회되는 경우"인 것 같은데, 이 부분은 Order.createOrder 생성자에서 처리해줄 수 있을 것 같거든요. (혹은 Order의 member컬럼을 not null로 설정하거나) 이유가 궁금합니다!
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
Autowired 질문드립니다.
Autowired 를 만약 Service에서 하게된다면 Service는 Repository를 DI해야하는것이 통상 개발하는 구조(?) 니까 자동으로 Spring은 Repository를 DI하는것같은 메소드(즉 Autowired) 된 것을 찾고 Autowired된 것들중에 Repository의 Class와 Service에서 Class가 일치하는것들 두개를 자동으로 주입시켜준다고 내부적 프로그래밍이 되어있다고 봐도 무방할까요?
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
bootstrap을 적용 안시켰는데 적용이 되었습니다.
안녕하세요! 야생형 커리큘럼 따라서 먼저 한번 듣고 두번째로 실전1 강의 듣고있습니다. 궁금한게 있어 질문드립니다. bootstrap같은 경우 프로젝트 내부 static 폴더에 css와 js 패키지를 다운로드 받아서 적용시키잖아요, 그런데 두 번째 시도에서 파일을 다운로드 받지도 않고 그냥 실행했는데 예쁘게 적용이 되어있는걸 확인할 수 있습니다. 아마 지난번에 만들었던 프로젝트가 영향을 준 것 같은데 어떻게 그럴수 있을까요? 혹시 캐싱 문제일까 해서 강력 새로고침을 해보기도 했는데 그 문제는 아닌 거 같습니다. 어떻게 이렇게 되는건지 혹시 가르쳐주실 수 있을까요? static 폴더가 비어있는 상태에서 localhost:8080 화면입니다!
-
해결됨Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
로그인을 다시 하지 않고 이전에 사용했던 JWT 토큰 사용
안녕하세요 ~ 26분에 user-service를 재실행하고 회원가입을 새로 한 다음에, 로그인을해서 JWT를 새로 발급받지 않고 기존 JWT를 사용하셨는데, JWT토큰은 만료기간만 지나지 않으면 계속 사용할 수 있는건가요??!
-
해결됨스프링 데이터 JPA
클래스 기반 프로젝션 사용 관련 질문
안녕하세요. 강의 내용대로 CommentSummary를 클래스 기반 프로젝션으로 그대로 넣어서 했는데 아래와 같은 오류가 나오네요. No converter found capable of converting from type [me.whiteship.demospringdatacommonweb.post.Comment] to type [me.whiteship.demospringdatacommonweb.post.CommentSummary] org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [me.whiteship.demospringdatacommonweb.post.Comment] to type [me.whiteship.demospringdatacommonweb.post.CommentSummary] at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322) at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) (중략) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56) at java.base/java.lang.Thread.run(Thread.java:829) CommentRepositoryTest > getComment() FAILED org.springframework.core.convert.ConverterNotFoundException at CommentRepositoryTest.java:38 사실 인터페이스 기반 프로젝션을 사용하면 될 문제이지만, 클래스 기반 프로젝션으로도 정상적으로 동작할거라 봤는데 동작을 안하네요. Spring 버전이 바뀌면서 클래스 기반 프로젝션을 사용할 수 없게 된걸까요?? 바쁘시겠지만 확인해주시면 감사하겠습니다.
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
@Autowired 를 통하여 여러개의 Repository 를 하나의 메소드에서 처리해도되나요?
안녕하세요, 강의잘보고있습니다. 여러가지 lombok 이나 다른 편의라이브러리를 사용하는것도 좋지만 아직은 구조잡기가 우선이라고 생각하여 최대한 필수구조를 잡아가며 짜는연습중인데 강의중에 Requirment... Annotation 을 사용하지않고 아래 방법대로 @Autowired 가 되어도 문제가없는지 질문드립니다. @Service@Transactional(readOnly = true)public class OrderService { private final MemberRepository memberRepository; private final OrderRepository orderRepository; private final ItemRepository itemRepository; @Autowired public OrderService(MemberRepository a, OrderRepository b, ItemRepository c) { this.memberRepository = a; this.orderRepository = b; this.itemRepository = c; }}
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
MemberRepository, ItemRepository 차이점
안녕하세요 영한님! Item 엔티티는 처음 저장할 때 id 값이 없다고 하셨는데 Member 엔티티도 똑같지 않나요..? 두 엔티티의 차이점이 잘 이해가 되질 않습니다 ㅠㅠ
-
미해결실전! Querydsl
N+1 현상
안녕하세요 영한님 잘보고있습니다. 감사합니다 질문이 하나 있습니다. public List<MemberTeamDto> searchByBuilder(MemberSearchCondition condition){ BooleanBuilder builder = new BooleanBuilder(); if(StringUtils.hasText(condition.getUsername())){ builder.and(member.username.eq(condition.getUsername())); } if(StringUtils.hasText(condition.getTeamName())){ builder.and(team.name.eq(condition.getTeamName())); } if(condition.getAgeGoe() != null){ builder.and(member.age.goe(condition.getAgeGoe())); } if(condition.getAgeLoe() != null){ builder.and(member.age.loe(condition.getAgeLoe())); } return queryFactory .select(new QMemberTeamDto( member.id.as("memberId"), member.username, member.age, team.id.as("teamId"), team.name.as("teamName") )) .from(member) .leftJoin(member.team, team) .where(builder) .fetch(); } //페치조인 미 적용 테스트를 해보면 @Test public void searchTest(){ Team teamA = new Team("teamA"); Team teamB = new Team("teamB"); em.persist(teamA); em.persist(teamB); Member member1 = new Member("member1", 10, teamA); Member member2 = new Member("member2", 20, teamA); Member member3 = new Member("member3", 30, teamB); Member member4 = new Member("member4" ,40, teamB); em.persist(member1); em.persist(member2); em.persist(member3); em.persist(member4); MemberSearchCondition condition = new MemberSearchCondition(); condition.setAgeGoe(35); condition.setAgeLoe(40); condition.setTeamName("teamB"); List<MemberTeamDto> result = memberJpaRepository.searchByBuilder(condition); assertThat(result).extracting("username").containsExactly("member4"); } N+1 같은 현상이 일어나지 않습니다. 페치 조인을 사용하지 않았는데 이유가 있을까요 ?