묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결실전! 스프링 데이터 JPA
상황에 따라 DB table 칼럼이 추가 또는 변경시 jpa 에서 어떻게 다룰수 있나요?
안녕하세요 김영한님 오랜만에 질문을 남깁니다. 프로젝트 중간중간 jpa 관련 의문점이 들때마다 다시한번 책과 이 강좌가 많은 참고가 됩니다. 이 자리를 빌어 다시한번 감사드립니다^^ 제목에서처럼 테이블명과 기본 구조 칼럼은 그대로이나 상황에 따라 아래의 code000 칼럼의 갯수가 추가 또는 삭제가 되는 그런 구조인데 jpa에서 어떻게 다룰 수 있는지 궁금합니다.
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
JPA Count 쿼리 Return 값
안녕하세요 JPA 사용하다 궁금한게 생겨 질문드립니다.현재 강의를 듣고 Spring Data JPA를 사용중인데요공식 문서를 보니 count query 시 return 값이 Long(Wrapper Type)으로 반환된다 합니다.혹시나 싶어서 jpa에서 count 후 return class type을 보니 java.lang.Long으로 반환되네요....궁금한건 count는 sql도 그렇고 jpa 문서상에도 null인 경우가 없는것으로 보이는데요JPA에서 Count 쿼리 호출시 primitive가 아닌 Wrapper로 반환하는 이유가 있을까요??엔티티 ID처럼 nullable로 인한 이득이 있는것도 아닌데, 결과값을 박싱해서 내려주는게 어떤 이득이 있는지 모르겠습니다.마지막으로 Long으로 반환되는 결과값을 아래처럼 long으로 unboxing 해서 사용해도 성능이나 여러가지면에서 손해보는면이 있을까요?@Query("select count(m) from ....... wherer ....")long countMember();
-
해결됨Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
RestTemplate 나 FeignClient는 API GATEWAY는 통과하지 않나요?
항상 강의 잘 보고 있습니다. 제목 그대로 RestTemplate로 하나 FeignClient로 하나 Gateway log를 살펴보면 user-service만 호출되있네요. 이전에 RestTemplate에서는 url설정시에는 localhost:8000/order-service/%s...이런 식으로 url을 조합했다면 그 이후엔 url을 @LoadBalanced 어노테이션 붙이고 localhost 대신에 마이크로 서비스 이름을 넣었는데 이 방식과 Feign클라이언트로 하는 방식 모두 api gateway 에서는 order service의 로그가 안뜨더라구요. 원래 이 방식으로하면 gateway를 먼저 거쳐가는 게 아닌 마이크로서비스 간에 직접적으로 통신을 하게되나요. 감사합니다.
-
미해결스프링 데이터 JPA
JPA에서 테이블명을 변수값으로 받아와서 select하는 경우
안녕하세요. 강의를 보면서 이런저런 기능을 구현해보고 있는데요. 혹시 API에서 "/api/{TABLE_NAME}"으로 get 을 보내 받아온 TABLE_NAME과 일치하는 테이블을 찾아 해당 테이블의 값을 모두 findAll 하게 할 수 있나요? 복수의 테이블에 대하여 각각 findAll을 하고자 할때 테이블별로 API를 만드는 방법밖에 없는지 궁금합니다. 테이블마다 구조는 각각 다릅니다. 따라서 테이블마다 entity와 repository는 만들어줄 수밖에 없을 것같은데 {TABLE_NAME}을 해당하는 entity와 repository를 찾도록 분기문을 하는게 최선일까요? 네이티브 쿼리도 생각해 봤는데 가능하면 쿼리 사용안하고 해보고 싶은데 검색해봐도 잘 모르겠네요. 조언 부탁드립니다. 감사합니다.
-
해결됨실전! 스프링 데이터 JPA
@Transaction에 대한 궁금중
안녕하세요 영한님. 강의를 들으면서 문득 @Transaction의 위치와 중첩에 대해서 궁금중이 들어서 제 나름대로 몇가지 테스트를 해봤습니다. 첫 번째로, 리포지토리 레이어에 트랜잭션이 적용되어 있고 해당 리포지토리의 메서드를 사용하는 서비스 레이어에도 트랜잭션이 적용되어 있다면 flush는 두 레이어 중 어느 시점에 발생할까 궁금했습니다. 그래서 테스트를 해본 결과 최종적으로 서비스 레이어의 트랜잭션이 끝나는 순간에 모든 쿼리가 적용되는 것을 볼 수 있었습니다. 두 번째로, 위와 동일한 상황에 서비스 레이어의 트랜잭션 옵션만 readOnly라면 리포지토리의 save 메서드는 실제 db에 저장을 할까 궁금해서 테스트해봤습니다. 결과는 물론 서비스 레이어 트랜잭션이 우선이기에 insert 쿼리는 발생하지 않았습니다. 두 테스트를 통해서 트랜잭션 우선권은 좀 더 넓은 범위(?), 즉 요청과 응답에 가까운 레이어의 트랜잭션을 따라간다고 이해가 됩니다. 그렇다면 제 생각에는 컨트롤러에 트랜잭션을 적용한다면, OSIV를 사용하지 않아도 영속성 컨텍스트가 화면을 띄울 때까지 유지될 것 같은데 막상 해보면 no Session 에러를 뿜내요.. 컨트롤러에서 html 파일을 렌더링해서 반환하는게 아니라 컨트롤러에서 정적 파일로 일단 반환하고 트랜잭션이 종료된 후에 따로 렌더링하는 작업을 거쳐서 그런걸까요? 쓰다보니 말이 길어져서.. 죄송합니다 ㅎㅎ..
-
해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
강사님 다대다 설정과 개인프로젝트 적용에 대해 질문있습니다
강좌에는 카테고리-상품에 N:M 다대다 관계로 해놓으셨는데요! 제가 30살인데 29살에 퇴사하고 혼자 JPA공부해서 학교다니던 친구와 백1프론트1을 맡아서 프로젝트를 만들고있는데.. 1:N, N:1은 좀 해결했는데 N:M에서 막히고있어요ㅠㅠ 약간 힌트라도 주실 수 있으신지 해서 여쭤봅니다. 질문이 너무 많아서 힘드시면 직접적으로 말씀하셔도괜찮습니다..! 만약에 이런 경우는 어떻게 하나요? (1) ~한다,~되다의 V 중간테이블 1.여러명의 회원은 여러개의 게시글을 찜목록에 추가할 수 있다. 1-1. 여러명의 회원은 여러개의 공고를 찜목록에 추가할 수 있다. 1-2. 여러명의 회원은 여러개의 기업을 찜목록에 추가할수있다. USER(회원)과 기업/공고/게시글 엔티티 사이에 중간테이블을 놓고 유저ID랑, 각각 필요한 기업/공고/게시글 아이디로 매핑해놓은 상태인데요 - 검은색 이렇게 하는게 맞는지 궁금합니다. (2) ~한다,~되다의 V 중간테이블 [회원]은 여러개의 [이력서]로 [공고]에 [지원]할 수 있다라고 해서 이력서와 공고의 N:M관계를 해소하고자 중간테이블을 만들고 지원한다라는 APPLY 엔티티를 따로 만들었는데, JPA에서도 이렇게 하면 되는건가요..? (3) 중간테이블 질문 DB상으로는 외래키가 PK가 되면서 한 테이블안에 PK가 없어도 된다는 식으로 들었는데, 검색을해보니 JPK는 PK가 있어야된다하더라구요!? 만약에 N:M관계 중간에 중간테이블을 만들면 보통은 외래키 2개가 들어가는데, JPA식으로 만들면 PK, FK, FK해서 총 3개가 만들어지는게 맞나요? (4) intelliJ에서 DB연결을 하고 data Diagram Visualization으로 매핑관계를 살펴보니 이렇게 나오는데.. intelliJ나 datagrip에서는 흔히 까마귀발이라고 하는 1:N, N:1 관계는 안보여주더라구요..! 그리고 mysql workbench reverse engineer모드로 erd를 그려봤는데..여기에서는 1:1관계도 1:N으로 나오는데...(분명히 유저와 멤버는 @OneToOne으로 양방향 매핑했는데도 이렇게 나옵니다. 혹시 DB를 설계하면서 잘 되었는지 erd로 뽑아보고싶은데, 아직 완벽하게 보여주는 건 없는건가요..?
-
해결됨실전! 스프링 데이터 JPA
@Modifying에 관한 질문
안녕하세요 영한님!이번 강의로 Modifying 어노테이션의 clearAutomatically 옵션이 왜 필요한건지 잘 이해했습니다. 그런데 다른 옵션인 flushAutomatically는 제가 아는 상식과 충돌이 되서 질문드립니다.기본적으로 createQuery를 날리면 db에 직접 접근하여 처리하기 때문에 현재 영속성 컨텍스트의 1차 캐시에 있는 것들을 강제로 flush하고 작성한 쿼리를 날리는 것으로 이해를 하고 있습니다.벌크연산 역시 createQuery의 일종이라고 생각하기 때문에 flushAutomatically 옵션의 기본값은 true일 거라고 예상했는데 false로 되어있어서 헷갈립니다.1. Modifying에서 제공하는 자동 flush 옵션과 벌크 연산전에 자동으로 일어나는 flush는 의미가 서로 다른건가요?//추가: 구글링을 해본 결과, 두 flush는 같은 의미가 맞고 @Modifying 옵션 값과 상관없이 hibernate에서 강제로 flush를 해준다고 합니다.그리고 이건 질문은 아니고 제가 정리한게 맞는지 여쭤봅니다.강의 영상처럼 테스트 클래스의 한 @Transaction 안에서 멤버를 생성하고 벌크연산으로 변경하고 조회하는 것이 아니라서비스 레이어에서 각각의 @Transaction가 있는 메서드로 분리해서 테스트를 해봤는데, 여전히 동일한 현상이 일어나더라구요.2. 이것은 OSIV에 의해서 영속성 컨텍스트의 생명주기가 트랜잭션의 종료시점이 아닌 최종적으로 response를 뱉을때까지 유지되고, 1차 캐시 역시 유지되기 때문에 각각의 트랜잭션에서 실행되는 서비스 메서드 간에서도 1차 캐시가 공유된다는 뜻으로 이해하면 될까요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
테스트 오류 질문드립니다
안녕하세요 14:57초 쯤에서 진행하는 테스트에서 에러가 나는데 확인해주실 수 있을까요? 에러메시지는 아래와 같이 나옵니다. Could not write standard input to Gradle Test Executor 3. java.io.IOException: 파이프가 닫히는 중입니다 at java.base/java.io.FileOutputStream.writeBytes(Native Method) at java.base/java.io.FileOutputStream.write(FileOutputStream.java:354) at java.base/java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:81) at java.base/java.io.BufferedOutputStream.flush(BufferedOutputStream.java:142) at org.gradle.process.internal.streams.ExecOutputHandleRunner.forwardContent(ExecOutputHandleRunner.java:68) at org.gradle.process.internal.streams.ExecOutputHandleRunner.run(ExecOutputHandleRunner.java:53) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56) at java.base/java.lang.Thread.run(Thread.java:834) > Task :test FAILED Error: Could not find or load main class worker.org.gradle.process.internal.worker.GradleWorkerMain Caused by: java.lang.ClassNotFoundException: worker.org.gradle.process.internal.worker.GradleWorkerMain FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':test'. > Process 'Gradle Test Executor 3' finished with non-zero exit value 1 * Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights. * Get more help at https://help.gradle.org BUILD FAILED in 3s 4 actionable tasks: 1 executed, 3 up-to-date
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
gropingBy 에 관하여입니다.
Set<Map.Entry<OrderQueryDto, List<OrderItemQueryDto>>> entries = flats.stream() .collect(groupingBy(o -> new OrderQueryDto(o.getOrderId(), o.getName(), o.getOrderDate(), o.getOrderStatus(), o.getAddress()), mapping(o -> new OrderItemQueryDto(o.getOrderId(), o.getItemName(), o.getOrderPrice(), o.getCount()), toList()))) .entrySet(); 여기서 OrderQueryDto 와 Map 의 키(groupingby 의 classifier)가 되는 것 같은데 아무리 구글링해봐도 객체인경우에는 @EqualsAndHashCode를 통해 여러 필드중 특정 필드를 지정해줘야한다? 이런말을 못 찾겠습니다... 질문도 좀 이상한것 같은데 제가 궁금한것은 어떤 키워드나 사이트를 참조해서 공부해야하는지 입니다... 찾아본 예시들도 다 그냥 일반적인 경우라 어떻게 equalshashcode를 알려줘야하는지 원천? 을 알고싶습니다.
-
미해결스프링 데이터 JPA
JPA를 이용하여 DB 데이터 이용하기
안녕하세요. 좋은 강의 감사 드립니다. 예를들어 DB에 Table A, B, C가 있고, Table A, B, C의 구조는 모두 다릅니다. 이때 아래와 같은 쿼리를 JPA를 이용하여 구현하고 싶습니다. SELECT * FROM A; SELECT * FROM B; SELECT * FROM C; (물론 select 외에도 많은 쿼리를 날릴 예정입니다^^) 이런경우 Table A, B, C에 대하여 각각 Controller A, Repository A, Entity A Controller B, Repository B, Entity B Controller C, Repository C, Entity C 를 따로 만들어 줘야 하는 건가요?! 3개의 테이블에서 모두 select *를 하려고 하기 때문에 REST API에서 "/api/{TABLE_NAME}"으로 변수를 받아 {TABLE_NAME}에 맞춰 해당하는 테이블의 값을 갖고오도록 할 수 있는건가요?! 그런식으로 구현할 경우 어떤 방식으로 해야 하나요?! 테이블이 너무 많은데 해당 테이블마다 Contoroller, Repository, Entity Class를 각각 생성하는것이 정말 효율적인 방법인지 문의드립니다. 감사합니다.
-
미해결실전! Querydsl
페치 조인과 on 절
안녕하세요! 4:39초 코드에서 질문 있습니다. 코드를 left조인으로 수정, where절 대신 on절 추가로 코드를 바꿔봤습니다. on절로 걸러진 것들을 left join하고 Lazy인 것을 페치 조인으로 땡겨올 것이라 예상했는데 오류가 나더라구요 혹시나 해서 활용편을 다시 봤는데 fetch join 예시에서는 on을 사용하지 않으셨더라구요 fetchjoin은 on절과 사용하지 못하는 건가요? List<Member> findMembers = queryFactory .selectFrom(member) .leftJoin(member.team, team).fetchJoin().on(team.name.eq("teamA")) .fetch();
-
미해결실전! 스프링 데이터 JPA
insert에 대해서 문의드립니다.
안녕하세요 김영한님:) 실무 적용 중에 궁금한게 있어서 문의 드리는데요. 보통 entity내에 joinColumn이든 mappedBy든 연관관계를 성립 시켜주는데요 그냥 단순히(?) 주문생성(주문관련된 테이블들에 insert이 이루어짐)만 이루어진다면 굳이 연관관계 맵핑을 하지 않고 각 주문관련 테이블들에 하나씩 컨트롤 하면서 insert 하는게 편리할 것 같다는 생각이 들어서.. 이런 접근 방법이 맞을까요? 물론 테이블 간 FK로 묶여 있는 테이블들도 있긴 한데 이런 경우는 위 처럼 하면 JPA의 객제관점으로 테이블에 접근 하는 관점에서는 어긋나는것 같기도 하고...영한님의 의견은 어떠실까요? 참고로 이 서비스는 사실상 주문관련 테이블은 insert만 이루어지고 select는 상태값 정도 조회하는 신규 api 입니다. 쿼리가 아닌 JPA 관점에서 접근하는 게 생각보다 딱 이거다 이런게 명확하지 않으닌까 생각이 진짜 많아지는것 같아요 ㅠㅠ 감사합나다.
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
엔티티가 아닌 DTO로 변환을 할 때 컬렉션 조회를 할 경우 @JsonIgnore가 필요로 하는상태가 생겼습니다.
API 개발 고급 - 컬렉션 조회 최적화에서 주문 조회 V2: 엔티티를 DTO를 변환 수업에서 4:30 에 No properties문제가 발생하여 저도 getter를 넣었으나 다음과 같은 에러가 발생했습니다. 구글링 한 결과 해당 컬렉션이 지연 로딩으로 인해 프록시 객체를 serialize하기 때문에 나는 에러라고 합니다. 그래서 제가 조치한 것은 해당 에러가 발생하는 @OneToMany필드를 @JsonIgnore를 했습니다. 다행히 정상 작동은 했으나 김영한님의 강의에서도 그렇고 제가 개인적으로 하는 프로젝트에서도 단 한번도 Entity에 @JsonIgnore를 사용하지 않았습니다. 단순히 DTO에 getter를 사용했는데 작동이 잘 되었습니다. 어떻게 하면 Entity에 @JsonIgnore를 사용하지 않고 문제를 해결할 수 있을까요?
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
Entity 생성시 다른 애그리거트의 정보/로직이 필요한 경우 생성 방식의 선택 기준
안녕하세요. 이번 강의 내용에서 추가적인 요구사항을 적용해보는 중, 설계상 궁금증이 생겨 질문하게 되었습니다. jpashop에서는 환불제도 악용 회원의 주문을 일정 기간동안 금지할 수 있다는 요구사항을 추가했습니다. 이 변경된 요구사항을 위해, MemberStatus라는 VO를 Member 클래스에 추가했습니다. 결과적으로, Order 클래스를 생성함에 있어서 MemberStatus의 로직(다른 애그리거트의 Value Object)을 필요로 합니다. 이 때, 선택할 수 있는 생성 방식이 여러개가 떠올라서, 이들의 선택 기준에 대한 조언을 듣고 싶습니다. 첫번째 방식. 정적 팩토리 메서드의 매개변수로 추가 첫번째 방식은 생성시 필요한 정보를 가진 객체(MemberStatus)들을, 정적 팩토리 메서드의 매개변수로 전달합니다. 선택 기준은 객체(Order)를 생성함에 있어서, 특정 객체(MemberStatus)가 필요함을 명시적으로 알릴 수 있습니다. 생성로직을 해당 클래스가 전적으로 제어하는 것이 생성 로직을 한 곳에 더 응집시킬 수 있습니다. 이 두가지를 고려했습니다. 이 방식에서는 회원 차단에 따른동작 분기는 정적 팩토리 메서드 내에서 이루어집니다. 다만, Order를 생성하는데 있어서 MemberStatus 이외에도 협력해야 할 애그리거트들이 많이 존재하는 경우 Order 클래스가 너무 많은 의존성을 가지게 될 수 있다는 점이 우려됩니다. 두번째 방식. 생성을 위한 정보/로직을 가지고 있는 클래스가 생성을 담당 선택 기준은 Member가 Order를 생성하기 위한 로직(회원 차단 여부)을 제공합니다. 위 내용을 고려했습니다. 이 방식에서는 검증 통과 여부에 따른 동작 분기는 Member의 메서드 내에서 이루어집니다. 다만, 이 방식은 Member —> Order로의 불필요한 의존성을 만들어낼 수 있다고 우려했습니다 특히, 생성에 대한 책임을 맡는다는 것은 내부에 어떤 데이터를 가지고 있는지 전부 알아야 한다는 점에서 생각보다 과도한 의존성을 부여하고 있는 것 같습니다. 또한 협력해야 할 애그리거트가 많아질 수록, Member가 생성과 관련된 다른 클래스들에 대한 많은 의존성을 감당해야 한다는 점이 우려됩니다. 세번째 방식. 애그리거트를 생성하는 Domain Service를 만든다. 선택기준은 많은 의존성을 가져야 하는 생성 로직을 서비스에 담음으로서, 엔티티가 불필요한 의존성을 가지는 것을 방지합니다. 위 내용을 고려했습니다. 다만, 조금만 복잡해져도 도메인 서비스를 사용하고자 하는 유혹이 생겨서, 자칫하면 다른 로직들도 Domain Service로 구현해, Entity 자체의 응집성이 작아지는게 아닌가 우려스럽습니다. 질문 내용 정리 1. 각 생성 방식을 선택함에 있어서 미흡한 선택 기준에 대해서 조언 해주 실 수 있나요? 2. 또 첫번째, 두번째 방식이 우려하는 사항들은 현재의 사례에서는 잘 드러나지 않는 '잠정적인' 우려사항들인데, 실제로 이 우려사항들이 나타나기 전까지는 가장 간단한 구현(첫번째 혹은 두번째)을 그대로 사용해도 될까요?
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
JPA/Spring 동기화 문제와 관련하여 문의드립니다.
안녕하세요. 최근 JPA강의와 Spring boot강의를 연달아 들었는데요, 너무 좋은 강의 감사드립니다. 지금까지 영한님께 배운 내용을 토대로 Spring boot + jpa를 이용하여 사이드 프로젝트를 진행중인데, 동기화 문제와 관련해 문의드리고자 글남깁니다. 제가 문제를 겪은 시나리오는 아래 코드와 같습니다. 이 경우 여러 사용자가 동시에 요청하지 않는 경우에는 문제없이 잘 동작하지만, 동시에 많은 사용자가 접근하게 되는 경우에는 동기화 문제가 발생될 것으로 생각됩니다. ( 어떤 thread가 jpa context에 업데만 해놓고 commit하기전에 다른 스레드에서 쿼리를 통해 데이터를 가지고 온 경우.) 그렇다고 Controller layer에서 단순히 sync 키워드를 사용하게 되면 많은 사용자가 동시에 접근할때, 너무 느려지지 않을까 우려되기도 하는데, 어떤 방식으로 접근하는게 좋을지 조언 여쭙고자 질문드립니다. @Transactional boolean addInformation(Data data) { // 어떤 정보가 현재 DB에 쓰여져 있지 않은 경우에 한해 업데이트. List<Infomation> info infoRepository.findAllWith(data); if (info.size() > 1) return false; /// DB에 없으므로 db update ..... }
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
JPA에서의 올바른 엔티티 삭제 방법에 대해 질문 드립니다.
영한님 안녕하세요 :) 오래전에 공부 했던게 기억나지 않아서 예전에 봤던 강의를 돌고 돌다가 질문을 남기게 되었습니다. UPDATE는 더티체킹으로 변경하는 것에 대해서는 이해하고 적용을 하고 있는데, 효율적인 삭제 방법에 대해서는 감이 잡히지 않아서 이렇게 질문을 드립니다. 아래와 같은 간단한 상황을 예를 들면서 질문을 드리겠습니다. 위와 같은 도메인들이 있고, 각각은 모두 양방향 참조를 하고 있는 상황이라 가정 하겠습니다. 이 때 비즈니스 요구사항은 아래와 같습니다. 1. MEMBER 탈퇴 시에 해당 MEMBER에 연관된 POST도 모두 함께 삭제 되어야 한다. 2. 특정 CATEGORY 삭제 시 해당되는 POST는 남겨두고 CATEGORY만 삭제가 되어야 한다. 1번, 2번이 서로 조건이 상반 되는데요. 여기서 질문을 드리고 싶습니다. 질문 1) 1번 요구사항의 경우 orphanRemoval 혹은 Cascade를 통해 손쉽게 할 수 있을거 같습니다. Cascade를 적용 해놓았기 때문에 JpaRepository의 delete 메서드로 MEMBER를 지우면 해당되는 POST도 모두 지워질 듯 한데요. 이런 요구사항에서는 이렇게 지우는게 best practice가 맞는지 알고 싶습니다. 질문 2) Cascade All, orphanRemoval을 함께 사용하면 부모 엔티티와 자식 엔티티가 생명 주기를 함께 하면서 부모 엔티티가 자식 엔티티에 대한 모든 제어권을 가지는 것과 마찬가지라고 알고 있습니다. 그런데 앞선 질문1 처럼 삭제 할 때만 Cascade를 적용하고 싶다면 Cascade DELETE가 더 적합할 듯 한데요. 강의에서 DELETE는 많이 안쓴다고 언급 하셨습니다. DELETE를 잘 사용하지 않는 어떤 이유가 있는지 궁금 합니다! 질문 3) 위 요구사항에 의하면 MEMBER와는 다르게 CATEGORY는 부모 엔티티가 삭제 되어도 자식 엔티티인 POST를 그대로 남겨두어야 합니다. 이 때, CATEGORY의 POST List를 순회하면서 해당 POST에서 CATEGORY 와의 관계를 끊어주어야 할 듯 한데요. 반복문 또는 stream을 사용하면서 모든 관계를 끊어주어야 한다고 할 때, 성능상에 문제가 생기지는 않는지 궁금합니다. 예를 들어 CATEGORY가 10만개, 100만개의 POST와 연관관계를 가지고 있었다면, 이때는 어떤 방법으로 처리 하는지 알고 싶습니다. (JPQL로 직접 쿼리를 날리는 방법이 가장 먼저 떠오르는데, 무언가 JPA스러운(?) 우아한 방법이 있을거 같네요ㅎㅎ) 질문 4) 자식 엔티티를 가지지 않는 POST 엔티티를 삭제 할 때는 1. PostRepository의 delete를 직접 사용해서 지운다. 2. CATEGORY, MEMBER와의 관계를 null 처리 하고, 두 부모 엔티티 리스트에서 해당 POST를 지운다. 두 방법 모두 가능 가능할 듯 한데요. 어떻게 삭제를 하는 것이 best practice인지 알고 싶습니다. (+) 내용이 읽기 불편하실거 같아 개행을 많이 했는데도 게시판에 적용이 안되는 듯 하네요. 양해 부탁 드립니다ㅠㅠ 감사합니다.
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
DTO의 필요성이 와닿지 않습니다.
안녕하세요 강사님, 질문 드리겠습니다. DTO의 필요성에 대한 부분으로 "엔티티가 변경됐을 때 변경된 사항이 API 스펙에 적용되지 않아 API가 제대로 동작하지 않을 수 있다."라고 말씀해주셨는데요. 이러한 문제가 발생하는 V1에서는 받을 때는 Member, 돌려줄때는 CreateMemberResponse를 사용하고 있습니다. 그런데, 여기서 요청을 때, 응답을 줄 때 모두 Member를 사용해버린다면.. Member가 변경된다 하더라도 Response에서도 변경사항이 적용되기 때문에 문제가 없는 것 아닌가?? 하는 생각이 듭니다. 이 부분에 대한 추가설명을 부탁드리고 싶습니다. 감사합니다! ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ 이어지는 강의들을 듣다보니 자연스럽게 이해되었습니다. 이해한 바를 바탕으로 질문에 대한 자답을 해보자면.. ************************************************** DTO를 반드시 사용해야 하는 이유는 다음과 같다. 1. DTO를 사용하지 않을 경우 엔티티의 변경에 의해 API 스펙이 변경될 수 있다. -> 엔티티와 API가 일대일 대응의 관계를 가진다면 엔티티에 수정이 일어날 때마다 API 스펙을 일일히 변경해줘야한다. 이는 매우 번거로운 작업이며 컴파일 에러로 이를 감지할 수 없기 때문에 에러 원인을 찾기가 어렵다. (DTO를 사용하면 DTO -> 엔티티 과정에서 컴파일 에러가 발생되므로 엔티티의 변경사항을 반드시 파악할 수 있다) 2. 하나의 엔티티에 대해서 API는 여러 개가 존재할 수 있다. -> 각각의 API가 요구하는 엔티티에 대한 데이터는 모두 다를 확률이 높다. 이때, 그냥 엔티티의 모든 정보를 넘겨줘버린다면 필요없는 데이터까지 받긴 하지만 필요한 건 전부 받은 셈이니 기능 동작에는 문제가 없을 것이다. 하지만 PW처럼 보안상 감추어야 할 정보까지 모두 JSON으로 함께 넘어가기 때문에 보안 문제가 발생할 수 있다. 엔티티 측에서 컬럼에 @JsonIgnore를 사용해 JSON 전달을 막을 수는 있지만 이는 엔티티가 API 스펙에 의존성을 갖게 되므로 좋지 않다. 유지보수가 복잡해질 뿐 아니라 다른 API에 대해서는 그때그때 또 변경을 해줘야 하는 쓸 데 없는 번거로움이 발생한다. 3. 엔티티를 그대로 넘겨줄 경우, 엔티티가 가진 정보 외의 것들은 넘겨주지 못한다. -> DTO를 사용하면 엔티티의 정보 외에 추가적으로 필요한 정보도 함께 넘겨줄 수 있다. ************************************************** 이 정도가 될 것 같습니다만.. 제가 놓친 내용이 있을까요??
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
JPA 관계 설정
안녕하세요! HTTP강의듣고 이번에 JPA강의도 듣네요 명강의 감사합니다. 계속 고민하다 궁금한게 생겨서 여쭤봅니다. Post Reply 관계에서 N : 1 그래프 객체가 Reply에있는 상태에서 강의에서 공부한대로, 혼자공부한대로 최대한 단방향으로 설정하려합니다. 근데 항상 고민이 됬던 것은 Reply를 save할 때, 해당 Post를 갖고와서. 즉, url : post/1/reply - @PostMapping 으로 Reply를 만들고자할때 Service단에서 ( 여기서 코딩하는거라 오타가있을수도...) @Transactional public void saveReply(ReplyServiceDto serviceDto){ // 우선적으로 post : 1 을 불러와서 Post post = postRepository.find(serviceDto.getPostId); Reply reply = Reply.builder() .postId(post) .content(serviceDto.getContent) build(); replyRepository(reply); } 이런식으로 하면 항상 reply를 save할때 post를 갖고와야한다는 불편함이있습니다. 그리고 url또한 post/1/reply 가아닌 reply 로 할때는 어떻게해야하는지... 그래서 찾아본 결과 1. Reply 쪽에 private Long postId; 딱 이것만 설정해놓고 따로 Post는 설정안하는 방법이 있더라구요. 물론 이게 무결성에 안좋다는건 알고있습니다. 2. 반대로 그냥 Post post 부분을 referencedColumn , DynamicInsert를 통해 null 로 넣을수도있다는... ( 이부분을 계속 시도는해보지만 FK로 안되는중 ) 너무 길었습니다. 결론은 그겁니다. 어떻게 해야 DB에 가는 성능상의 이슈를 풀수있는가. reply를 저장할때마다 post를 꼭 불러와야하는가. 이것에 대한 문제입니다. 그리고 한 post에 여러 reply가 달린 프로젝트에선 양방향은 또 어떨지... 궁금합니다 항상 좋은강의 감사합니다.
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
JPA 매핑에 대해 궁금한게 있습니다.
보통 클래스 1개당 Entity 도 1개가 일반적인 상황인데 Mongo DB 같은경우 한 개의 Collection에 모든 Data 를 담으면 오히려 DB 역할이 퇴색되기 때문에 여러 Collection(Table)으로 나누곤 하는데요. 그러면 같은 Class 형태에 이름이 다른 경우는 어떻게 할 수 있을 까요? @Entity(name = "A")public class TestA { @Id private Long id; private String data;} @Entity(name = "B")public class TestA { @Id private Long id; private String data;} ... @Entity(name = "Z")public class TestA { @Id private Long id; private String data;} 위와 같이 A~Z 까지 테이블이 모두 동일한데 한개의 class 로 관리하고 싶습니다. only read 로만 사용할 건데 방법이 없을까요?
-
미해결실전! 스프링 데이터 JPA
update 관련해서 질문 드립니다.
안녕하세요. 김영한님:) 영한님의 JPA강의를 들으면서 실무에 바로바로 적용하는 중에 있는데요. 1. 엔티티에 setter를 사용 하지 않고 수정 및 데이터 저장시 entity내에 메소드를 만들어서 사용하는걸 권장해주셨는데, 큰 덩어리(?)에 entity에서 하나의 컬럼만 수정이 될 때도 말씀주신 메소드를 만들어서 사용 하는게 좋을까요? 2. prodQty = prodQty + 1 이렇게 바로 DB 컬럼만으로 update가 가능한것도 select한 것을 param으로 넘겨서 메소드로 만들어서 하는게 좋은걸까요? 개인적으로 repository내에 @Modifying을 이용해서 만드는게 더 가식적인고, 한개의 업데이트를 사용하기에도 더 편리해보인다는 라는 생각도 들어서요(물론 @Modifying은 벌크성 update에 주로 이용한다고 하셨지만...) JPA에 익숙하지 않는 습성(?)때문에 그렇게 느껴지는 부분일까요? 더티체킹이라는 JPA는 장점을 살리지 못한 생각일까요? 강의 들을때 이해가 퐉퐉! 되었는데 막상 실무에선 작은것도 많은 고민을 하게 되네요 ㅠㅠ 감사합니다.