월 24,200원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
일대다 조인 시 쿼리 궁금증
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용][1. 일대다 조인]em.createQuery("select m from Team t join t.members m" , Member.class).getResultList();Member이 N이고 Team이 1일 때 일대다 조인으로 JPQL 쿼리를 Member만 조회되게 작성하면 Member 뿐만 아니라 Team까지 동시에 조회되는 것을 확인할 수 있었습니다. [2. 다대일 조인]em.createQuery("select m from Member m join m.team t" , Member.class).getResultList(); em.createQuery("select t from Member m join m.team t" , Team.class).getResultList();위와 같이 다대일 조인에선 제가 원하던대로 Member 조회 시 Member에 대한 조회 쿼리만 나가고 Team 조회 시 Team에 대한 조회 쿼리만 나가는 것을 확인할 수 있었습니다. [핵심 질문]다대일로 조인할 때는 제가 지정한 객체만 조회되는 것을 알 수 있었습니다.왜 일대다로 조인할 때는 [1.일대다 조인] 처럼 Member 뿐만 아니라 Team 까지 덩달아 조회되는 건지 궁금합니다 !※ 테스트는 전부 지연 로딩으로 진행하였고, [1. 일대다 조인]에서의 결과는 즉시 로딩과 지연 로딩 상관 없이 같은 결과가 나왔습니다.※ 각 테스트 간 독립성 확보를 위해 em.flush() , em.clear()로 영속성 컨텍스트를 깨끗하게 하면서 진행하였습니다.
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
cascade와 고아객체 질문있습니다.
@Entity @Getter @Setter public class Parent { @Id @GeneratedValue private Long id; private String name; @OneToOne(mappedBy = "parent") private Child child; public void addChild(Child child) { this.child = child; child.setParent(this); } } @Entity @Getter @Setter public class Child { @Id @GeneratedValue private Long id; private String name; @OneToOne @JoinColumn(name = "parent_id") private Parent parent; } 1. Parent와 child코드가 위와 같을 때 아래 코드에서 에러가 발생하는 이유는 양방향 매핑인데 child를 insert하지 않으니 Parent에 있는 child가 없는 것이 되므로 에러가 발생하는 것이 맞나요?Parent parent = new Parent(); Child child = new Child(); parent.addChild(child); em.persist(parent); ------------------------------------------------------------------------------- 2. mappedBy가 양방향 연관관계를 맺어주는 건데 단순히 아래와 같이 Parent에 있는 mappedBy를 없애면 단방향 연관관계로 바뀌는 건가요?(아래와 같이 단순히 mappedBy만 없앤 것과 child를 없앤것은 똑같이 단방향을 의미하게 되는 건가요?) public class Parent { @Id @GeneratedValue private Long id; private String name; // // mappedBy 만 없다면 이것도 child -> Parent 단방향이 되는 건가요? 아니라면 이 코드는 무슨 의미가 되는 코드인가요? @OneToOne private Child child; public void addChild(Child child) { this.child = child; child.setParent(this); } } public class Parent { @Id @GeneratedValue private Long id; private String name; public void addChild(Child child) { this.child = child; child.setParent(this); } } -------------------------------------------------------------------------------@Entity @Getter @Setter public class Parent { @Id @GeneratedValue private Long id; private String name; @OneToOne(mappedBy = "parent", fetch = FetchType.LAZY) private Child child; public void addChild(Child child) { this.child = child; child.setParent(this); } } @Entity @Getter @Setter public class Child { @Id @GeneratedValue private Long id; private String name; @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "parent_id") private Parent parent; public void addChild(Child child) { this.child = child; child.setParent(this); } } 3. 위의 코드와 같이 Parent, Child에 둘 다 fetch = FetchType.LAZY를 안하면 아래코드 실행시 join이 발생하는데 왜 발생하는 건가요?(Parent를 조회하는 것이니 Child에 LAZY를 해주어서 child를 조회하지 않게 한다는 것은 이해가 되는데 왜 Parent에도 LAZY를 해주어야 하나요?Parent의 @OneToOne이 EAGER라고 해도 Parent 조회하는 것만 EAGER이니 Parent에는 LAZY를 안해도 되것 같은데 왜 LAZY를 해주어야 하는지 궁금합니다.)Parent parent = new Parent(); Child child = new Child(); parent.addChild(child); em.persist(parent); em.persist(child); em.flush(); em.clear(); Parent findParent = em.find(Parent.class, parent.getId()); ------------------------------------------------------------------------------- 4. 3번 질문 코드에서 em.find() 때 쿼리를 보면 select parent와 select child를 하는데 select child 쿼리는 왜 나가는 건가요? LAZY로 동작하지 않고 EAGER로 동작하는 것 같은데 왜 그런건가요? ------------------------------------------------------------------------------- @Entity @Getter @Setter public class Parent { @Id @GeneratedValue private Long id; private String name; @OneToOne(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL) private Child child; public void addChild(Child child) { this.child = child; child.setParent(this); } } @Entity @Getter @Setter public class Child { @Id @GeneratedValue private Long id; private String name; @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "parent_id") private Parent parent; public void addChild(Child child) { this.child = child; child.setParent(this); } } 5. 강의에서와 같이 리스트인 child를 삭제하려면 findParent.getChildList().remove(0); 과 같이 하는데, @OneToOne의 경우에는 어떻게 하면 되나요? 아래와 같이 Parent의 child 값을 null로 만든 뒤에 remove를 하면 delete 쿼리가 나가는데 이렇게 하면 될까요? 혹시 다른 좋은 방법이 있을까요?Child child1 = findParent.getChild(); findParent.setChild(null); em.remove(child1); 그리고 아래 코드와 같이 하면 삭제가 왜 안되는 건가요?Parent findParent = em.find(Parent.class, parent.getId()); em.remove(child);
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
주 테이블 대상 테이블이 뭔가요?
더 자주 접근하는 테이블을 주 테이블이라고 일컫는건가요?
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
양방향 매핑 시 stackoverflow 발생
[질문 템플릿]1. 예2. 예3. 예[질문 내용]양방향 매핑 시 순환 참조때문에 toString 메서드에서 StackOverflowError가 발생할 수 있는데, toString 메서드에서 연관관계 참조 부분은 제외하는 방법으로 해결해서 사용하는 것이 일반적인가요?toString 메서드는 AutoValue나 IDE의 도움을 받아 작성하는 것이 일반적인 방법이라고 알고 있는데(이펙티브 자바 등등), 위 방법처럼 stackoverflow만 피하는 것이 옳은 방법인지 궁금해서 질문합니다.
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
HQL과 JPQL의 관계
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)예[질문 내용]안녕하세요 HQL과 JPQL의 관계를 정확히 알고 싶습니다.https://docs.jboss.org/hibernate/orm/4.3/devguide/en-US/html/ch11.htmlThe Hibernate Query Language (HQL) and Java Persistence Query Language (JPQL) are both object model focused query languages similar in nature to SQL. JPQL is a heavily-inspired-by subset of HQL. A JPQL query is always a valid HQL query, the reverse is not true however.Both HQL and JPQL are non-type-safe ways to perform query operations.라고 되어있는데, 그럼 hibernate 구현체에서 JPQL을 작성하게 되면 hibernate에서 내부적으로 이를 해석한 후 HQL로 변환해서 처리하는 것인가요?OKKY - JPQL 에서 limit 절이 왜 저는 될까요??JPQL에서 limit절 지원 안된다는 내용을 접했었는데 해당 글에서 처럼 limit을 추가하니 작동을 잘됐습니다. 그래서 찾아보니 HQL이 이를 지원한다라고 되어있는데.. JPQL에선 지원이 안되는데 HQL에서는 지원이 된다라는 내용이 좀 이해가 잘 안가서 둘의 관계에 의문을 갖게 되었습니다 감사합니다
- 해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
Hello JPA - 애플리케이션 개발 강의 질문드립니다.
안녕하세요!다름 아니라 [Hello JPA - 애플리케이션 개발 강의]를 따라가면서 하고 있는데, 강의와 다르게 나옵니다ㅠㅠ이런 식으로 id 1L인 member를 먼저 등록한 다음, 드래그 한 부분의 id를 2L로 바꿔주고 다시 서버를 띄우면강사님께서는서버를 다시 띄워도 이렇게 1L과 2L이 나오는데 저는 서버를 다시 띄우면2L만 나옵니다. rollback을 안 했는데도 id 2만 등록되어있습니다. 그리고이렇게 했을 때 강사님께서는 위에 아이디 1과 2의 member가 등록되어있는 상태에서 돌리셨기 때문에System.out.println("findMember.id = " + findMember.getId()); System.out.println("findMember.name = " + findMember.getName());이 부분이 잘 출력되는데 저는 rollback이 되어출력이 안 됩니다.. 무슨 차이일까요?강사님께서 제공해주신 <최신 프로젝트 설정하기>로 다운로드 받아 진행하였습니다.
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
변경 감지 메커니즘에서 4. flush, 5. commit 의미
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]여기에 질문 내용을 남겨주세요.사진에서 4. flush, 5. commit은 무엇을 의미하는 것인지 궁금합니다.
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
Transactional 과 Lazy Loading
안녕하세요 강의 잘 듣고 있습니다. 다름이 아니라 프로젝트를 업그레이드 하는 과정에서 오류가 생겨 질문 드립니다. package ShopProject.myShopProject.Domain; import ShopProject.myShopProject.Domain.Item.Item; import ShopProject.myShopProject.Domain.Order.Order; import jakarta.persistence.*; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; import lombok.Getter; import lombok.Setter; import java.util.ArrayList; import java.util.List; @Entity @Getter @Setter public class Member { @Id @GeneratedValue @Column(name = "member_id") private Long id; private String name; @Embedded private Address address; @OneToMany(mappedBy = "member",cascade = CascadeType.REMOVE) private List<Order> orders = new ArrayList<>(); private String loginId; private String password; @OneToMany(mappedBy = "member") private List<LikedItem> likedItems = new ArrayList<>(); } package ShopProject.myShopProject.Domain; import ShopProject.myShopProject.Domain.Item.Item; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; @Entity @Getter @Setter public class LikedItem { @Id @GeneratedValue @Column(name = "likedItem_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") private Member member; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "item_id") private Item item; } 보시는 것처럼 멤버와 좋아요 상품은 Lazy 관계에 있습니다. OneToMany는 기본이 Lazy이므로 명시하지 않았습니다.따라서 좋아요 상품은 직접 조회될 때만 DB에서 조회되고, 다른 경우는 프록시 형태로 존재합니다. //아이템 상세 정보 @GetMapping("item") public String itemDetail(@RequestParam("itemId") Long itemId, @SessionAttribute(name = "loginMember") Member loginMember, Model model) { log.info("item 호출"); Item item = itemService.findOne(itemId); log.info(loginMember.getLoginId() + " " + loginMember.getName()); // 좋아요 여부 추가 model.addAttribute("isLiked", memberService.isliked(loginMember, item)); //이 부분입니다!! model.addAttribute("item", item); model.addAttribute("member", loginMember); if (item.getCategory().equals("Book")) { return "items/item/book"; } if (item.getCategory().equals("Album")) { return "items/item/album"; } if (item.getCategory().equals("Movie")) { return "items/item/movie"; } return "items/item"; } 위 컨트롤러를 호출하면, isliked라는 매소드를 실행하게 됩니다. 좋아요 여부를 확인하는 메소드입니다. //좋아요 아이템이 아니면 false 반환 @Transactional public Boolean isliked(Member member, Item item) { log.info("좋아요 확인 메서드 실행"); // log.info("멤버 정보" + member.getName() + " " + member.getLoginId()); for (LikedItem likeditem: member.getLikedItems()) { //여기에서 lazyinitializationError 발생 if (likeditem.getItem().getName().equals(item.getName())) { log.info("좋아요인 경우"); return true; } } log.info("좋아요 아닌 경우"); return false; } 그런데 여기에서 맴버의 좋아요 목록을 불러오면 lazyinitialization 에러가 발생합니다... 정말 많이 원인도 구글링해보았는데, 영속성 컨텍스트가 종료 된 후 접근할 때 발생하는 것을 알았습니다.영속성 컨텍스트의 생명주기는 트렌잭션과 거의 동일하다고 알고 있습니다. 만약 위 메소드에 트렌젝션 어노테이션이 없다면 member.getLikedItems() 의 결과를 초기화해주지 않으면 오류가 발생할 것입니다. 따라서 트렌젝션 어노테이션을 넣으므로서, member.getLikedItems()를 가져오고, 직접 DB에서 불러오는 과정을 한 트랜젝션 안에서 수행하도록 했습니다. 그런데 이 메서드에서 계속 LazyinitializatoinError가 발생합니다. 이 부분의 원인을 전혀 못 찾겠습니다.. 해결책으로는 DTO를 사용하거나, fetch Join을 사용해서 멤버와 같이 조인하여 한번에 가져옴으로 해결할 수있을 거라 생각합니다. 하지만 해결책은 알았지만, 위 코드의 무슨 오류가 있는지 정말 궁금합니다. 따라서 이 코드의 오류를 알고 싶습니다. 또한 저의 이해에 오류가 있다면 그 부분도 알려주시면 감사하겠습니다.
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
스냅샷은 어느 영역에 있는건지궁금합니다.
1차 캐시는 jvm heap 메모리 영역에 올라간다는 글을 보았는데요. 그렇다면 스냅샷은 어느 영역에 올라가는건지 궁금합니다 1차 캐시와 같은 영역인지 별도의 다른 영역에 존재하게 되는지..
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
auto 설정시 drop 에러
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. INFO: HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)Hibernate: drop table Member cascade constraintsHibernate: create table Member ( id number(19,0) not null, grade varchar2(255 char), name varchar2(255 char), primary key (id) )5월 22, 2024 4:56:36 오후 org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnectionINFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@4e83a98] 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.5월 22, 2024 4:56:36 오후 org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl handleExceptionWARN: GenerationTarget encountered exception accepting command : Error executing DDL " drop table Member cascade constraints" via JDBC [Table "MEMBER" not found;]org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL " drop table Member cascade constraints" via JDBC [Table "MEMBER" not found;] at 최초 자동 생성할 때 Member 테이블이 존재 해야 하나요 ??저는 Member 테이블이 없어서 drop 할 수 없다고 하는거 같은데 Member 테이블이 없어도 auto 옵션을 켜놓으면 자동으로 생성되어야 하는 개념 아닌가요 ???
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
값타입은 비록 인스턴스가 달라도 그 안에 값이 같으면 같은 것으로 봐야 한다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]"값 타입은 비록 인스턴스가 달라도 그 안의 값이 같다면 같은 것으로 보아야 한다"위 문장의 전과 후의 맥락은 모두 이해하였는데, 이 문장이 어떠한 철학에서 나온 내용인지 궁금합니다.예를 들어서 완전히 동일한 내용을 가진 address를 저장한 두 멤버가 있을 때,Address address1 = new Address("city")member1.setAddress(address1);Address address2 = new Address("city")member2.setAddress(address2); 다음의 결과가 나와야 한다는 의미인가요?findAdd1 = em.find(Member.class, member1.getId()).getAddress(); findAdd2 = em.find(Member.class, member2.getId()).getAddress(); findAdd1.equals(findAdd2) -> true ??
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
양방향 연관관계와 연관관계의 주인1 - 기본 7분 내용 문의
em.flush();em.close();까지 진행하고 디비를 조회하면 데이터가 들어간 것이 확인이 됩니다. 그러나 Member findMember = em.find(Member.class, member.getId()); 까지 코드를 실행시키면 db에 값이 들어가지 않아서 결과적으로 for(Member m : Members) { System.out.println("m = " + m.getUsername();} 프린트문이 찍히지 않습니다. 해당 문제 관련하여 코드를 첨부합니다. 좋은 답변 부탁드리겠습니다 ㅠㅠ https://drive.google.com/file/d/1Y6wHODqbUjAcB035pgx0sZabI1n3rkqg/view?usp=drive_link
- 해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
준영속 상태로 만들기
[질문 템플릿]1. 예2. 예3. 예[질문 내용]Member member = em.find(Member.class, 150L); member.setName("AAAAA"); em.detach(member); tx.commit();이 코드에서 setName에서 영속성 컨텍스트에 있는 member에 수정이 발생했고, 이를 스냅샷과 비교하여 dirty checking을 합니다. UPDATE 쿼리는 쓰기 지연 SQL 저장소에 저장됩니다.위 과정이 모두 끝난 이후에 detach를 하더라도 UPDATE 쿼리는 쓰기 지연 SQL 저장소에 있을텐데, UPDATE 쿼리가 나가지 않는 이유는 flush할 때 영속성 컨텍스트에서 관리하는 엔티티가 아닌데 생성된 쿼리는 거르고 DB로 날리는 메커니즘으로 작동하는 건가요?
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
실행 시 시퀸스 자동 생성
질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]여기에 질문 내용을 남겨주세요.단방향 연관관계 강의 9:40에서 이전에 작성했던 시퀸스 모두 삭제하고 다시 작성해서 실행했는데 에러가 떠서 drop SEQUENCE MEMBER_SEQ;로 h2 디비에서 시퀸스를 지우고 다시 실행했습니다. 근데 왜 실행할 때 아래와 같이 각 테이블에 대한 시퀸스가 자동으로(1 increment by 50으로) 생성되는건가요? 강의에서는 1 increment by 1로 생성됩니다.
- 해결됨자바 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보다 사용이 더 적은건가요??
- 미해결자바 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를 할 때, 프록시 객체가 아니라, 왜 한꺼번에 엔티티를 들고오는지 궁굼합니다..!
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
엔티티 타입과 값 타입은 JPA 에 한정해서 구분해놓은 데이터 타입인가요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]값 타입 비교를 언급하시면서, 클래스를 사용한 임베디드 타입의 경우 참조값이 아닌 값 자체 비교를 위해 재정의된 equals 메서드를 사용한다고 말씀해주셨습니다. 제가 헷갈리는 부분은, 자바 언어에서 타입을 비교할 때 "기본형(통상 값) 타입", "참조형 타입" 이라는 워딩을 사용하기 때문입니다. 그래서 참조형 타입인 임베디드 클래스가 JPA 에서 값 타입으로 설명되는게.. 어떤 이유인지 생각해보니 JPA 에 한정해서 데이터 타입을 엔티티 타입, 값 타입으로 나누기 때문이지 않을까 라고 생각했습니다. 따라서 임베디드 타입의 경우 자바 언어 관점에서 보았을때는 참조형 타입이고, JPA 의 관점에서 보았을 때는 엔티티 타입이 아니므로 값 타입으로 보면 된다고 이해했는데 맞는지 궁금합니다! 시원하게 정리가 안되네요..
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
질문 있습니다
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 지금 개발하시는 jpa는 스프링 jpa가 아닌 순수 jpa로 개발하시는 건가요?
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
경로 표현식을 사용하면 묵시적 조인에 해당하나요?
경로 표현식을 사용한다는 것은 묵시적 조인을 사용하는 것과 같은 의미인가요?