묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
결과 쿼리 개수가 맞지 않아서 문의 드립니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용][간단한 주문 조회 V3: 엔티티를 DTO로 변환 -패치 조인 최적화] 강의에서 5분 50초 쯤에 v2를 돌려봤을 때, 강사님은 쿼리가 5번 나오는데,저는 계속 7번이 나오더라구요...order가 처음에 주문 2개를 만들어서 이미 영속성 상태라 그 다음에는 1차 캐시에서 가져오는 것으로 보여 쿼리는 생성이 안되어야 한다고 생각이 드는데, 왜 계속 order 쿼리가 2번 더 나오는 걸까요...? [Query]2023-10-25T21:54:33.448+09:00 DEBUG 37176 --- [nio-8080-exec-3] org.hibernate.SQL :selecto1_0.order_id,o1_0.deliver_id,o1_0.member_id,o1_0.order_date,o1_0.statusfromorders o1_0joinmember m1_0on m1_0.member_id=o1_0.member_idfetchfirst ? rows only2023-10-25T21:54:33.449+09:00 INFO 37176 --- [nio-8080-exec-3] p6spy : #1698238473449 | took 0ms | statement | connection 11| url jdbc:h2:tcp://localhost/~/jpashop2select o1_0.order_id,o1_0.deliver_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 join member m1_0 on m1_0.member_id=o1_0.member_id fetch first ? rows onlyselect o1_0.order_id,o1_0.deliver_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 join member m1_0 on m1_0.member_id=o1_0.member_id fetch first 1000 rows only;2023-10-25T21:54:33.450+09:00 DEBUG 37176 --- [nio-8080-exec-3] org.hibernate.SQL :selectm1_0.member_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.namefrommember m1_0wherem1_0.member_id=?2023-10-25T21:54:33.451+09:00 INFO 37176 --- [nio-8080-exec-3] p6spy : #1698238473451 | took 0ms | statement | connection 11| url jdbc:h2:tcp://localhost/~/jpashop2select m1_0.member_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.name from member m1_0 where m1_0.member_id=?select m1_0.member_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.name from member m1_0 where m1_0.member_id=1;2023-10-25T21:54:33.451+09:00 DEBUG 37176 --- [nio-8080-exec-3] org.hibernate.SQL :selectd1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.statusfromdelivery d1_0whered1_0.delivery_id=?2023-10-25T21:54:33.451+09:00 INFO 37176 --- [nio-8080-exec-3] p6spy : #1698238473451 | took 0ms | statement | connection 11| url jdbc:h2:tcp://localhost/~/jpashop2select d1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.status from delivery d1_0 where d1_0.delivery_id=?select d1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.status from delivery d1_0 where d1_0.delivery_id=1;2023-10-25T21:54:33.452+09:00 DEBUG 37176 --- [nio-8080-exec-3] org.hibernate.SQL :selecto1_0.order_id,o1_0.deliver_id,o1_0.member_id,o1_0.order_date,o1_0.statusfromorders o1_0whereo1_0.deliver_id=?2023-10-25T21:54:33.452+09:00 INFO 37176 --- [nio-8080-exec-3] p6spy : #1698238473452 | took 0ms | statement | connection 11| url jdbc:h2:tcp://localhost/~/jpashop2select o1_0.order_id,o1_0.deliver_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 where o1_0.deliver_id=?select o1_0.order_id,o1_0.deliver_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 where o1_0.deliver_id=1;2023-10-25T21:54:33.453+09:00 DEBUG 37176 --- [nio-8080-exec-3] org.hibernate.SQL :selectm1_0.member_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.namefrommember m1_0wherem1_0.member_id=?2023-10-25T21:54:33.453+09:00 INFO 37176 --- [nio-8080-exec-3] p6spy : #1698238473453 | took 0ms | statement | connection 11| url jdbc:h2:tcp://localhost/~/jpashop2select m1_0.member_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.name from member m1_0 where m1_0.member_id=?select m1_0.member_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.name from member m1_0 where m1_0.member_id=2;2023-10-25T21:54:33.453+09:00 DEBUG 37176 --- [nio-8080-exec-3] org.hibernate.SQL :selectd1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.statusfromdelivery d1_0whered1_0.delivery_id=?2023-10-25T21:54:33.454+09:00 INFO 37176 --- [nio-8080-exec-3] p6spy : #1698238473454 | took 0ms | statement | connection 11| url jdbc:h2:tcp://localhost/~/jpashop2select d1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.status from delivery d1_0 where d1_0.delivery_id=?select d1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.status from delivery d1_0 where d1_0.delivery_id=2;2023-10-25T21:54:33.454+09:00 DEBUG 37176 --- [nio-8080-exec-3] org.hibernate.SQL :selecto1_0.order_id,o1_0.deliver_id,o1_0.member_id,o1_0.order_date,o1_0.statusfromorders o1_0whereo1_0.deliver_id=?2023-10-25T21:54:33.454+09:00 INFO 37176 --- [nio-8080-exec-3] p6spy : #1698238473454 | took 0ms | statement | connection 11| url jdbc:h2:tcp://localhost/~/jpashop2select o1_0.order_id,o1_0.deliver_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 where o1_0.deliver_id=?select o1_0.order_id,o1_0.deliver_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 where o1_0.deliver_id=2; [OrderSimpleApiController]package jpabook.jpashop2.api;import jpabook.jpashop2.Repository.OrderRepository;import jpabook.jpashop2.Repository.OrderSearch;import jpabook.jpashop2.domain.Address;import jpabook.jpashop2.domain.Order;import jpabook.jpashop2.domain.OrderStatus;import lombok.Data;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;/*** X To One (컬렉션 X)* Order* Order -> Member* Order -> Delivery*/@RestController@RequiredArgsConstructorpublic class OrderSimpleApiController {private final OrderRepository orderRepository;@GetMapping("/api/v1/simple-orders")public List<Order> ordersV1(){List<Order> all = orderRepository.findAllByString(new OrderSearch());for (Order order : all) {order.getMember().getName(); // Lazy 강제 초기화order.getDelivery().getAddress(); // Lazy 강제 초기화}return all;}@GetMapping("/api/v2/simple-orders")public List<SimpleOrderDto> ordersV2(){// Order 2개List<Order> orders = orderRepository.findAllByString(new OrderSearch());List<SimpleOrderDto> result = orders.stream().map(o -> new SimpleOrderDto(o)) // map : a -> b로 치환.collect(Collectors.toList());return result;}@GetMapping("/api/v3/simple-orders")public List<SimpleOrderDto> ordersV3() {List<Order> orders = orderRepository.findAllWithMemberDelivery();List<SimpleOrderDto> result = orders.stream().map(o -> new SimpleOrderDto(o)).collect(Collectors.toList());return result;}@Datastatic class SimpleOrderDto{ // API 명세서private Long orderId;private String name;private LocalDateTime orderDate;private OrderStatus orderStatus;private Address address;public SimpleOrderDto(Order order) {orderId = order.getId();name = order.getMember().getName();orderDate = order.getOrderDate();orderStatus = order.getStatus();address = order.getDelivery().getAddress();}}} [OrderRepository]... public List<Order> findAllWithMemberDelivery() {return em.createQuery("select o from Order o" +" join fetch o.member m" +" join fetch o.delivery d", Order.class).getResultList();}
-
해결됨Practical Testing: 실용적인 테스트 가이드
null 검증
안녕하세요! 우빈님. 테스트 강의에서 많은 인사이트를 얻고 갑니다! 작은 고민이 하나 있는데요! 우빈님은 어떻게 생각하시는지 궁금하여 여쭈어봅니다!바로 도메인 객체에서의 null 검증인데요!BeanValidation을 통해서 Presentation에서 검증을 하더라도, 도메인 단에서 또 null 검증을 해주어야 하는가에 대한 질문입니다. 팀원들과 팀플을 하다보면 @NotNull 을 이용하여 Presentation 단에서 검증이 될텐데, 도메인에서도 null 검증을 해주어야 하는가!? 에 대한 질문을 많이 받습니다. 개인적으로 저는 Presentation 단에서 검증이 되더라도 실제로 객체가 생성될 때 까지의 일련의 과정들 속에서 객체에 온전한 값이 들어가지 않을 것 같아 null 체크 또한 해주는 것이 안정적인 코드를 만들어 줄 수 있다고 생각하는 편인데요! 이러한 작업들이 그래도 비용이 들어가는 측면이라, 개발 속도에 영향을 미쳐서 그런지 선호하지 않는 분들도 종종 만났던 것 같습니다! 혹시 우빈님 생각은 어떤지 의견을 한 번 여쭈어보고 싶습니다
-
미해결Practical Testing: 실용적인 테스트 가이드
현재 시간에 의존하는 코드
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요. 테스트 강의를 보고 실천(?)하고 있는 개발자입니다!최근 현재 시간에 대한 테스트를 짜던 도중, 현재 시간을 모킹하는 방법이 있다는 걸 알게 됐습니다. 우빈님 강의에서는 현재시간을 파라미터로 받는 방식을 통해 테스트를 짜셨는데, 두 가지 방법에 대해 어떻게 생각하시는지 의견이 궁금합니다!
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
일대다 관계 제약조건 일경우
현재 일대다 관계에서 member테이블 update되는 걸 확인하였습니다. 업무 특성상 별도로 h2 데이터베이스를 사용하지 않고 교육을 청강중에 있습니다. h2DB를 봤을때는 기본키를 제외하고 별도의 제약조건이 존재하지 않은것으로 보여지는데요. 테이블에 외래키 제약조건이 있을 경우 일대다 관계가 에러없이 성립이 가능한가요?특정 프로젝트의 경우 설계 당시에 관계를 잡아놓고, 오픈 시점에서 보안 또는 속도를 이유로 관계를 끈어놓을 경우가 있는데 관계 없는 사용하기 것도 가능한것인지 궁금합니다.
-
미해결스프링과 JPA 기반 웹 애플리케이션 개발
알림 아이콘redirect 인경우
안녕하세요redirect 의 경우를 제외시켜주셨는데 이게 가능한 이유가redirect 는A -> B로 리다이렉트 한다고 가정하면A에 담긴 모델을 B한테 그대로 가져가서 가능하다고 이해했는데맞을까요 ?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
그레이들 빌드 실패..
Execution failed for task ':JpashopApplication.main()'. > Process 'command '/Library/Java/JavaVirtualMachines/jdk1.8.0_321.jdk/Contents/Home/bin/java'' 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. Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0. You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. For more on this, please refer to https://docs.gradle.org/8.3/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. BUILD FAILED in 5s 3 actionable tasks: 1 executed, 2 up-to-date 4강 듣고있는데 롬복, 어노테이션 설정까지 똑같이 따라 햇는데.. 왜 안되는 걸까요
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
더티채킹 이후 save 호출시 문제가 있을까요?
안녕하세요! 회사에서 mysql, Spring Data JPA를 사용하고있습니다.레거시 코드를 볼때마다 트랜잭션안에서 엔티티 속성값을 변경한 다음, 추가로 save 메서드를 호출해서 변경된 엔티티를 저장해주더라고요. 이러한 방식이 문제가 될 이유라면 뭐가있을지 궁금합니다!
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
BeanCreationException 에러
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (아니오)[질문 내용]여기에 질문 내용을 남겨주세요.스프링부트 버전 3.x 이상이고 Junit5를 사용해서 build.gradle에 useJUnitPlatform() 추가하고 테스트에서 @RunWith 대신 @ExtendWith를 사용했습니다.그리고 나머지는 자료 그대로 따라했는데 실행시켜보면Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: jakarta/xml/bind/JAXBException이런 에러가 뜨네요.뭐가 문제일까요..?
-
해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
21:59에 lazy 초기화 오류
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]21:59초에 영상 내용을 따라 Lazy 초기화 후에 포스트맨을 검색해보았는데 출력이 되지 않고 오류가 떠서 질문드립니다.. 오류를 보아하니 무한루프가 돌아가는것 같은 느낌도 듭니다..오류내용java.lang.IllegalStateException: Cannot call sendError() after the response has been committed 2023-10-24 12:44:32.150 ERROR 46125 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]->jpabook.jpashop.domain.Delivery["order"]->jpabook.jpashop.domain.Order["delivery"]-> initDbpackage jpabook.jpashop; import jpabook.jpashop.domain.*; import jpabook.jpashop.domain.Item.Book; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import javax.annotation.PostConstruct; import javax.persistence.EntityManager; @Component @RequiredArgsConstructor public class InitDb { private final InitService initService; @PostConstruct public void init() { initService.dbInit1(); initService.dbInit2(); } @Component @Transactional @RequiredArgsConstructor static class InitService { private final EntityManager em; public void dbInit1() { Member member = createMember("userA", "서울", "1", "1111"); em.persist(member); Book book1 = createBook("JPA1 BOOK", 10000, 100); em.persist(book1); Book book2 = createBook("JPA2 BOOK", 20000, 100); em.persist(book2); OrderItem orderItem1 = OrderItem.createOrderItem(book1, 10000, 1); OrderItem orderItem2 = OrderItem.createOrderItem(book2, 20000, 2); Order order = Order.createOrder(member, createDelivery(member), orderItem1, orderItem2); em.persist(order); } public void dbInit2() { Member member = createMember("userB", "진주", "2", "2222"); em.persist(member); Book book1 = createBook("SPRING1 BOOK", 20000, 200); em.persist(book1); Book book2 = createBook("SPRING2 BOOK", 40000, 300); em.persist(book2); Delivery delivery = createDelivery(member); OrderItem orderItem1 = OrderItem.createOrderItem(book1, 20000, 3); OrderItem orderItem2 = OrderItem.createOrderItem(book2, 40000, 4); Order order = Order.createOrder(member, delivery, orderItem1, orderItem2); em.persist(order); } private Member createMember(String name, String city, String street, String zipcode) { Member member = new Member(); member.setName(name); member.setAddress(new Address(city, street, zipcode)); return member; } private Book createBook(String name, int price, int stockQuantity) { Book book = new Book(); book.setName(name); book.setPrice(price); book.setStockQuantity(stockQuantity); return book; } private Delivery createDelivery(Member member) { Delivery delivery = new Delivery(); delivery.setAddress(member.getAddress()); return delivery; } } } OrderSimpleApiControllerpackage jpabook.jpashop.api; import jpabook.jpashop.domain.Order; import jpabook.jpashop.repository.OrderRepository; import jpabook.jpashop.repository.OrderSearch; import lombok.RequiredArgsConstructor; import org.aspectj.weaver.ast.Or; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * XToOne * Order * Order -> Member * Order -> Delivery */ @RestController @RequiredArgsConstructor public class OrderSimpleApiController { private final OrderRepository orderRepository; @GetMapping("/api/v1/simple-orders") public List<Order> ordersV1(){ List<Order> all = orderRepository.findAllByString(new OrderSearch()); for (Order order : all) { order.getMember().getName(); //Lazy 강제 초기화 order.getDelivery().getAddress(); //Lazy 강제 초기화 } return all; } } JpashopApplicationpackage jpabook.jpashop; import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @SpringBootApplication public class JpashopApplication { public static void main(String[] args) { SpringApplication.run(JpashopApplication.class, args); } @Bean Hibernate5Module hibernate5Module(){ Hibernate5Module hibernate5Module = new Hibernate5Module(); return hibernate5Module; } }코드도 같이 올렸습니다.. 무엇이 다른건지 잘 모르겠습니다..
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
h2 버그인가요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]저는 ddl auto를 create로 하고시퀀스 전략 했을 때,persist 안하고 봐도 시퀀스가 그냥 1,증가가 50입니다..그 다음 persist를 한번 해 봤더니,next value for member_seq를 한번만 호출했습니다. 근데 persist 2번 이상하면,next value for member_seq를 2번 호출합니다.시퀀스의 현재값도 101번이 됩니다.뭔가 JPA쪽에서 놓친건가요..?아니면 제가 뭔가 강의에서 놓친건가요?그렇게 현재값 101번 만든 후,이번엔 dll.auto를 none으로 해서다시 돌려봤더니 다서 persist 해서 테이블에 저장해서 나온 건 52부터 찍힙니다. persist 안한 것 persist 1번next value for member_seq 한번 호출 persist 2번 호출next value for member_seq가 두번 호출 됍니다. 그런데.. 이 상태에서 ddl.auto를 none으로 하고 다시 한번 로직을 실행해 봤더니.. 어.. 제 생각이 맞다면 101부터 id가 매겨져야 할 것 같은데.. 어.. public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); try{ Member member1 = new Member(); member1.setUsername("A"); Member member2 = new Member(); member2.setUsername("B"); Member member3 = new Member(); member3.setUsername("C"); em.persist(member1); em.persist(member2); // em.persist(member3); tx.commit(); } catch (Exception e){ tx.rollback(); } finally { em.close(); } emf.close(); } 사용 버전<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jpa-basic</groupId> <artifactId>ex-hello-jpa</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-core</artifactId> <version>6.2.9.Final</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>2.1.214</version> </dependency> </dependencies> </project>
-
해결됨JPA & Spring Data JPA 기초
10강 3:37 질문
@Access는 JPA가 엔티티 데이터에 접근하는 방식을 지정하는 에너테이션으로 알고 있습니다.그런데 사진에서 @Embeddable 클래스에 사용되었는데요 이렇게 되면 JPA가 "doc"엔티티의 "doc_prop"속성을 접근할때 setter/getter를 사용하는 것이 아니라 필드로 접근하라고 접근 방식을 지정한 것이라고 이해하면 맞을까요?
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
@Rollback(value = false)을 설정해야 sql문이 로깅되나요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]@Test @Transactional @Rollback(value = false) public void testMember() throws Exception { //given System.out.println("given"); Member member = new Member(); member.setUsername("memberA"); //when System.out.println("when"); Long saveId = memberRepository.save(member); Member findMember = memberRepository.find(saveId); //then System.out.println("then"); Assertions.assertThat(findMember.getId()).isEqualTo(member.getId()); Assertions.assertThat(findMember.getUsername()).isEqualTo(member.getUsername()); Assertions.assertThat(findMember).isEqualTo(member); }위의 코드에서 @Rollback(value = false)없이 돌렸을때,given when 2023-10-23T22:09:28.313+09:00 DEBUG 13164 --- [ main] org.hibernate.SQL : select next value for member_seq then @Rollback(value = false)을 넣고 돌렸을 때,given when 2023-10-23T22:10:13.319+09:00 DEBUG 18292 --- [ main] org.hibernate.SQL : select next value for member_seq then 2023-10-23T22:10:13.456+09:00 DEBUG 18292 --- [ main] org.hibernate.SQL : insert into member (username,id) values (?,?) 위와 같이 출력됩니다.이 현상에 대해 제가 생각하는 원인은 다음과 같습니다.트랜잭션이 커밋될 때 (특정 상황 제외), 영속성 컨텍스트의 sql문들이 DB로 전송되므로, @Rollback(value = false)없는 상태에선 저장된 sql문들이 전달되지 않고 메모리에서 삭제되는 것으로 추론하고 있습니다.저의 생각이 맞는지 궁금합니다.
-
해결됨쥬쥬와 함께 하루만에 시작하는 백엔드 - 스프링, 도커, AWS
Spring Initializr 스프링 버전
강의에서 Spring Boot 3.0.6 버전 선택하라고 하시는데지금 Spring Initializr 사이트에 3.0.6 버전이 없네요.어떤 걸 선택하면 될까요?
-
미해결생산성을 향상시키는 스프링부트 기반의 API 템플릿 프로젝트 구현
전역 에러 처리 메시지 관리
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 강의에 보면 enum에 TEST라고 하시고 에러메시지를 정적으로 입력하셨는데 , 메시지properties로 따로 관리하는 방법은 없을까요?TEST(HttpStatus.INTERNAL_SERVER_ERROR,"001",messageSource.getMessage("001")),001 = "business Exception test" 돌아가는 코드는 아니지만 이런식으로 답변 주시면 감사하겠습니다
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
category item 관련 질문
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]다대다 연관관계가 안좋다해서 중간 엔티티로 categoryitem을 만들어서 해보고있는데 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: Shop.ShopingMall.domain.Category.category_item in Shop.ShopingMall.domain.CategoryItem.categories 이러한 오류가 떴습니다.. 해결방법이 뭘까요?? 코드는 다음과 같습니다 package Shop.ShopingMall.domain; import lombok.Getter; import lombok.Setter; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity @Getter @Setter public class Category { @Id @GeneratedValue @Column(name = "category_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "category_item_id") private CategoryItem categoryItem; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "parent_id") private Category parent; @OneToMany(mappedBy = "parent") private List<Category> child = new ArrayList<>(); } package Shop.ShopingMall.domain; import Shop.ShopingMall.domain.Item.Item; import lombok.Getter; import lombok.Setter; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity @Getter @Setter public class CategoryItem { @Id @GeneratedValue @Column(name = "category_item_id") private Long id; @OneToMany(mappedBy = "category_item") private List<Category> categories = new ArrayList<>(); @OneToMany(mappedBy = "category_item") private List<Item> items = new ArrayList<>(); } package Shop.ShopingMall.domain.Item; import Shop.ShopingMall.domain.CategoryItem; import lombok.Getter; import lombok.Setter; import javax.persistence.*; @Entity @Getter @Setter public class Item { @Id @GeneratedValue @Column(name = "item_id") private Long id; private String name; private int price; private int stockQuantity; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "category_item_id") private CategoryItem categoryItem; }
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
일대일 관계에서의 연관관계의 주인
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]연관관계의 주인을 외래키에 두라고 하신말씀은 알겠습니다.그것이 일대다 인경우는 자동차와 바퀴의 예를 들면서 말씀해주셔서 알겠는데 1대1관계의 경우 어느쪽이 외래키라고 할수 있는걸까요? 오더와 딜리버리의 경우에 오더가 관계의 주인이 되었는데 왜? 라고 물으면 잘 모르겠습니다만약에 예를들어 유저와 유저정보간의 관계가 있다면 그경우의 연관관계의 주인은 어떤것일까요?기준을 좀만 더 정확하게 알려주셨으면 좋겠습니다...
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
BindingResult에 관해
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]강의 잘 듣고 있습니다! 학습을 위해 예제 코드를 조금 응용해서 TODO 앱를 만들어보고 있는데 의도한 기능대로 작동이 안 됩니다. 강의 내용과는 조금 방향이 다르지만 BindingResult 관련 질문이기도 하고 하루종일 해봐도 모르겠어서 질문 올립니다. 강의 예제의 [회원 가입] 폼에서 이름을 비워두고 제출한 경우 @Valid 검증 오류가 발생 하여 return "members/createMemberForm" 되고, View에서 <p th:if="${#fields.hasErrors('name')}" th:errors="*{name}"><p>가 삽입되면서 MemberForm의 @NotEmpty 에러 메세지가 출력되는 기능을 조금 바꿔서 해 수정 기능에 적용해 보려고 했습니다. 의도한 기능은 이렇습니다. (코드는 밑에 있습니다)할 일(task) 수정을 누르면 @GetMapping("/tasks/{taskId}/edit")와 매핑된 메서드가 전달된 파라미터의 taskId로 할일 객체를 찾아 TaskForm(할일 Form 객체)에 값을 세팅합니다. 그리고 이 TaskForm 객체를 Model에 "form"이라는 이름으로 값을 담아 전달합니다.View(할일 수정 폼)에서 수정하고자 하는 할일의 현재 name 값, priority 값를 보여줍니다. (수정을 위해 현재 값을 표시해줌)수정 폼을 채우고 제출을 누르면 @PostMapping("/tasks/{taskId}/edit")에 매핑됩니다. 만약 검증에 오류가 있는 경우 return "task/editTaskForm";를 합니다. 즉 editTaskForm.html 문서를 엽니다. 문제 상황 :그런데 editTaskForm.html 파싱에 실패합니다. 해당 Task의 현재 값을 미리보기 해주려면 ${form.name}을 참고해야 하는데 form이 넘어가지 않아서 인 것 같습니다. 그래서 @SessionAttributes("form")로 세션에 저장해주었습니다(스프링 2.7입니다).2. 이제 파싱은 되고 해당 Task의 현재 값 미리보기도 됩니다. 그런데 여전히 <p> 태그가 생성되지 않아서 오류 메세지도 출력이 안 됩니다. BindingResult가 날아간 것 같습니다.3.방법을 바꿔서 View를 바로 여는 게 아니라 @GetMapping으로 리다이렉트를 해보았는데 역시 Model이 초기화되면서 BindingResult가 날아가는 것 같습니다 ㅠㅠ검색해보니 RedirectAttributes를 써야 한다는데 저는 강의와 똑같이 스프링 2.7을 쓰고 있는데 3.1 미만 버전에서는 GET 파라미터로 전달하는 것 외엔 방법이 없을까요? @Controller @RequiredArgsConstructor @SessionAttributes("form") public class TaskController { private final TaskService taskService; @ModelAttribute("form") public TaskForm getTaskFrom() { return new TaskForm(); } @GetMapping("/tasks/{taskId}/edit") public String editTaskForm(@PathVariable Long taskId, Model model) { Task task = taskService.findOne(taskId); TaskForm form = new TaskForm(); form.setName(task.getName()); form.setPriority(task.getPriority()); model.addAttribute("form", form); return "task/editTaskForm"; } @PostMapping("/tasks/{taskId}/edit") public String editTask(@PathVariable Long taskId, @Valid TaskForm form, BindingResult result, SessionStatus sessionStatus) { if (result.hasErrors()) { return "task/editTaskForm"; } taskService.editTask(taskId, form.getName(), form.getPriority()); sessionStatus.setComplete(); return "redirect:/tasks"; } } JPA 활용 2편까지도 들었고 MVC 1까지도 들었는데.. MVC 2의 BindingResult 강의를 듣고 다시 해보는게 좋을까요?하지만 너무 해결하고 싶습니다.........🥺 어느 부분을 체크해보면 좋을까요?
-
미해결실전! Querydsl
정렬 조건에 대해 질문이 있습니다.
public enum Tier { CHALLENGER("challenger"), GRANDMASTER("grandmaster"), MASTER("master"), DIAMOND("diamond"), EMERALD("emerald"), PLATINUM("platinum"), GOLD("gold"), SILVER("silver"), BRONZE("bronze"), IRON("iron"), NULL("null"); private final String tier; Tier(String tier) { this.tier = tier; } }이런 enum을 필드로 가지고 있는 entity가 있습니다.public class MyEntity { ... @NotNull @Column(name = "queue", columnDefinition = "VARCHAR(20)") @Enumerated(EnumType.STRING) private Tier queue; ... } 그런데 querydsl로 이 enum기준으로 custom sort를 할 경우에는 어떻게 해야하나요?예를 들면 enum Tier에 적혀있는 순서대로 CHALLENGER > GRANDMASTER > ... > NULL 순서대로 정렬할 때 어떻게 해야하는지 궁금합니다!
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
JPA1편 -> JPA2편 -> 기본편 순으로 학습해도 될까요?
김영한 강사님 추천 로드맵 수강 순서를 보면 JPA1편 -> 기본편 -> JPA1편 복습 -> JPA2편으로 되어있는데요 제 시간 사정상 최대한 빨리 익혀야 하기도 하고, API 설계나 DTO가 너무 궁금해서 곧바로 JPA2편으로 학습하고 싶습니다.JPA1편에서 모르는 개념들(영속성 컨텍스트, 머지, 도메인 설계)이 많아서 우선 그냥 코드 따라하기 식으로 하고 있는데요JPA2편까지 따라하다가 기본편 다시 봐도 될까요?
-
미해결Practical Testing: 실용적인 테스트 가이드
OrderRepositoryTest에서 발생한 에러
package sample.cafekiosk.spring.domain.order; @ActiveProfiles("test") @DataJpaTest class OrderRepositoryTest { @Autowired private OrderRepository orderRepository; @Autowired private ProductRepository productRepository; @DisplayName("특정 주문 상태에 따라 주문을 조회한다") @Test void findOrdersBy() { //given Product product1 = createProduct("아메리카노", 3000, HANDMADE, SELLING); Product product2 = createProduct("카페라떼", 4000, HANDMADE, SELLING); Product product3 = createProduct("카푸치노", 5000, HANDMADE, SELLING); List<Product> products = List.of(product1, product2, product3); LocalDateTime startTime = LocalDateTime.of(2023, 10, 19, 0, 0); LocalDateTime orderTime = LocalDateTime.of(2023, 10, 19, 10, 0); LocalDateTime endTime = LocalDateTime.of(2023, 10, 20, 0, 0); Order completedOrder = createOrder(orderTime, PAYMENT_COMPLETED, products); Order canceledOrder = createOrder(orderTime, CANCELED, products); // when List<Order> orders = orderRepository.findOrdersBy(startTime, endTime, PAYMENT_COMPLETED); // then assertThat(orders).hasSize(1) .extracting("id", "orderStatus", "totalPrice", "registeredDateTime") .containsExactlyInAnyOrder( tuple(1L, PAYMENT_COMPLETED, 12000, orderTime) ); } private Product createProduct(String name, int price, ProductType productType, ProductSellingStatus productSellingStatus) { Product product = Product.builder() .name(name) .price(price) .type(productType) .sellingStatus(productSellingStatus) .build(); return productRepository.save(product); } private Order createOrder(LocalDateTime now, OrderStatus orderStatus, List<Product> products) { Order order = Order.builder() .products(products) .orderStatus(orderStatus) .registeredDateTime(now) .build(); return orderRepository.save(order); } @DisplayName("찾고자 하는 시간 안에 있는 주문을 조회한다") @Test void findOrdersBy2() { //given Product product1 = createProduct("아메리카노", 3000, HANDMADE, SELLING); Product product2 = createProduct("카페라떼", 4000, HANDMADE, SELLING); Product product3 = createProduct("카푸치노", 5000, HANDMADE, SELLING); List<Product> products = List.of(product1, product2, product3); LocalDateTime startTime = LocalDateTime.of(2023, 10, 19, 0, 0); LocalDateTime orderTime = LocalDateTime.of(2023, 10, 19, 10, 0); LocalDateTime endTime = LocalDateTime.of(2023, 10, 20, 0, 0); LocalDateTime overTime = LocalDateTime.of(2023, 10, 20, 10, 0); Order completedOrder = createOrder(orderTime, PAYMENT_COMPLETED, products); Order overTimeOrder = createOrder(overTime, PAYMENT_COMPLETED, products); // when List<Order> orders = orderRepository.findOrdersBy(startTime, endTime, PAYMENT_COMPLETED); // then assertThat(orders).hasSize(1) .extracting("id", "orderStatus", "totalPrice", "registeredDateTime") .containsExactlyInAnyOrder( tuple(1L, PAYMENT_COMPLETED, 12000, orderTime) ); } }각각 Test 수행할 땐 정상적으로 잘 동작했습니다. 하지만, 같이 Test을 수행하는 경우 findOrdersBy()에서 아래와 같은 에러가 발생하고 있습니다2023-10-20 23:12:40.519 INFO 8704 --- [ main] o.s.t.c.transaction.TransactionContext : Began transaction (1) for test context [DefaultTestContext@1a6c1270 testClass = OrderRepositoryTest, testInstance = sample.cafekiosk.spring.domain.order.OrderRepositoryTest@2d114d27, testMethod = findOrdersBy@OrderRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@18a136ac testClass = OrderRepositoryTest, locations = '{}', classes = '{class sample.cafekiosk.spring.CafeKioskApplication}', contextInitializerClasses = '[]', activeProfiles = '{test}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@560348e6, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@6f1c29b7, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@fb58afcf, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@7b7fdc8, [ImportsContextCustomizer@77d67cf3 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, eJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@27d5a580, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@0], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@40d10264]; rollback [true] Hibernate: insert into product (id, created_date_time, modified_date_time, name, price, product_number, selling_status, type) values (default, ?, ?, ?, ?, ?, ?, ?) Hibernate: insert into product (id, created_date_time, modified_date_time, name, price, product_number, selling_status, type) values (default, ?, ?, ?, ?, ?, ?, ?) Hibernate: insert into product (id, created_date_time, modified_date_time, name, price, product_number, selling_status, type) values (default, ?, ?, ?, ?, ?, ?, ?) Hibernate: insert into orders (id, created_date_time, modified_date_time, order_status, registered_date_time, total_price) values (default, ?, ?, ?, ?, ?) Hibernate: insert into order_product (id, created_date_time, modified_date_time, order_id, product_id) values (default, ?, ?, ?, ?) Hibernate: insert into order_product (id, created_date_time, modified_date_time, order_id, product_id) values (default, ?, ?, ?, ?) Hibernate: insert into order_product (id, created_date_time, modified_date_time, order_id, product_id) values (default, ?, ?, ?, ?) Hibernate: insert into orders (id, created_date_time, modified_date_time, order_status, registered_date_time, total_price) values (default, ?, ?, ?, ?, ?) Hibernate: insert into order_product (id, created_date_time, modified_date_time, order_id, product_id) values (default, ?, ?, ?, ?) Hibernate: insert into order_product (id, created_date_time, modified_date_time, order_id, product_id) values (default, ?, ?, ?, ?) Hibernate: insert into order_product (id, created_date_time, modified_date_time, order_id, product_id) values (default, ?, ?, ?, ?) Hibernate: select order0_.id as id1_2_, order0_.created_date_time as created_2_2_, order0_.modified_date_time as modified3_2_, order0_.order_status as order_st4_2_, order0_.registered_date_time as register5_2_, order0_.total_price as total_pr6_2_ from orders order0_ where order0_.registered_date_time>=? and order0_.registered_date_time<? and order0_.order_status=? 2023-10-20 23:12:40.621 INFO 8704 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test: [DefaultTestContext@1a6c1270 testClass = OrderRepositoryTest, testInstance = sample.cafekiosk.spring.domain.order.OrderRepositoryTest@2d114d27, testMethod = findOrdersBy@OrderRepositoryTest, testException = java.lang.AssertionError: [Extracted: id, orderStatus, totalPrice, registeredDateTime] Expecting actual: [(3L, PAYMENT_COMPLETED, 12000, 2023-10-19T10:00 (java.time.LocalDateTime))] to contain exactly in any order: [(1L, PAYMENT_COMPLETED, 12000, 2023-10-19T10:00 (java.time.LocalDateTime))] elements not found: [(1L, PAYMENT_COMPLETED, 12000, 2023-10-19T10:00 (java.time.LocalDateTime))] and elements not expected: [(3L, PAYMENT_COMPLETED, 12000, 2023-10-19T10:00 (java.time.LocalDateTime))] , mergedContextConfiguration = [MergedContextConfiguration@18a136ac testClass = OrderRepositoryTest, locations = '{}', classes = '{class sample.cafekiosk.spring.CafeKioskApplication}', contextInitializerClasses = '[]', activeProfiles = '{test}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTestContextBootstrapper=true}', contextCustomizers = 왜 id가 3인가요?? 저는 DataJpaTest을 수행하면 각각의 Test 마다 rollBack이 수행되어 id가 당연히 1이라고 생각했었습니다. 왜 3이 되는지 이해가 되지 않습니다