월 24,200원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
jpql 쿼리 실행 시 데이터베이스에서 바로 조회되나요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.em.createQuery("select m from Member m", Member.class);이 쿼리를 실행할 때 제가 생각했을때는 1차 캐시에 있는 멤버 객체들을 불러오면 되니까 플러시가 필요없다고 생각했는데 강의에서는 1차 캐시가 아니라 데이터베이스에서 바로 조회를 한다는 식으로 설명하는 듯했는데 어떤게 맞는건가요?
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
강사님 코드 그대로 했는데 결과가 다릅니다. @SequenceGenerator 값이 50씩 늘어나요.
[질문 내용]안녕하세요 김영한 강사님. 강의 잘 듣고 있습니다.실습도중 저는 강사님과 똑같은 코드임에도 불구하고 다르게 동작하게 되어 질문 남기게 되었습니다.GeneratedValue 전략에서IDENTITY 전략은 persist 하는 과정에서 바로 DB insert를 하는 것을 이해했고SEQUENCE 전략은 allocationSize를 통해 처음 call next value 2번 호출 후 -1 의 값이 나와야하는데 저는 -1이 되지 않습니다.create 으로 하고 실행하고 create-drop 하고 실행하고 아예 캐시 문제인가 하여, DB를 전부 드랍후 다시 해보았는데도 TEAM_ID ID NAME null 1 m4null 2 nullnull 3 nullnull 4 nullnull 52 m4null 53 nullnull 54 nullnull 55 null값이 이런식으로 저장됩니다. 강사님과 코드는 동일한데 무엇 때문에 이렇게 동작할까요?package hellojpa; import jakarta.persistence.*; /** * @author : ewjin * @fileName : Member * @since : 24. 6. 20. */ @Entity @SequenceGenerator(name = "MEMBER_SEQ_GENERATOR", sequenceName = "MEMBER_SEQ", initialValue = 1, allocationSize = 50) public class Member { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MEMBER_SEQ_GENERATOR") private Long id; @Column(length = 300) private String name; @ManyToOne @JoinColumn(name = "TEAM_ID") private Team team; public Long getId() { Class<? extends Member> a = getClass(); System.out.println(a); return id; } public Team getTeam() { return team; } public void setTeam(Team team) { this.team = team; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } package hellojpa; import jakarta.persistence.*; import org.hibernate.Transaction; import java.util.Arrays; import java.util.List; public class JpaMain { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); try { Member m1 = new Member(); m1.setName("m1"); Member m2 = new Member(); m1.setName("m2"); Member m3 = new Member(); m1.setName("m3"); Member m4 = new Member(); m1.setName("m4"); em.persist(m1); em.persist(m2); em.persist(m3); em.persist(m4); System.out.println("m1.getId() = " + m1.getId()); System.out.println("m2.getId() = " + m2.getId()); System.out.println("m3.getId() = " + m3.getId()); System.out.println("m4.getId() = " + m4.getId()); tx.commit(); } catch (Exception e) { System.out.println("에러남========================="); tx.rollback(); System.out.println(e.getCause()); System.out.println(e.getMessage()); System.out.println(e.getStackTrace()); e.printStackTrace(); } finally { em.close(); emf.close(); } } }
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
제가 이해를 잘 못한 건가요??
[질문 내용]Drug DrugNutrient Nutrient(Enum) 타입이렇게 다대다 관계입니다. (DrugNutrient) @Query("select d from Drug d join d.drugNutrientList dn where dn.standardNutrient IN :standardNutrients group by d,dn " + "order by count(dn) desc") List<Drug> findProperDrug(@Param("standardNutrients") List<StandardNutrient> standardNutrients);저는 이 쿼리를 실행하면 mysql 은 SELECT d.* FROM drug d JOIN drug_nutrient dn ON d.drug_id = dn.drug_id WHERE dn.standard_nutrient IN ('CARBON_HYDRATE','PROTEIN','CALCIUM') GROUP BY d.drug_id, dn.drug_nutrient_id ORDER BY COUNT(dn.drug_id) DESC;이렇게 쿼리가 나갈 것이라고 예상했습니다. 따라서 그렇기 때문에 당연히 drug_id 가 중복해서 나올 것이라고 예상했습니다.실제로도 mysql 에서 중복되게 나오고요! 그러나 JPQL 을 통하면 drug_id 1이 중복해서 나오지 않습니다. 제가 쿼리를 잘 못 이해하고 있을까요? group by 에 무언가 있을 것 같긴 한데 놓친 내용이 있을 까요???실제 쿼리는 이렇게 나갑니다. select d1_0.drug_id, d1_0.drug_img_path, d1_0.english_name, d1_0.name, d1_0.url, d1_0.vendor from drug d1_0 join drug_nutrient dnl1_0 on d1_0.drug_id=dnl1_0.drug_id where dnl1_0.standard_nutrient in (?, ?, ?) group by d1_0.drug_id, dnl1_0.drug_nutrient_id order by count(dnl1_0.drug_nutrient_id) desc그리고 여담인데 group by 를 통하면 default batch fetch size 가 적용이 안되나요?1쪽에서 다쪽을 get 해서 사용했을 때 쿼리가 나가면서 Where 쪽에 In 쿼리가 바바박 나오던 걸로 기억합니다. List<Drug> findMoreSuitableDrugList = drugRepository.findProperDrug(standardNutrients); return findMoreSuitableDrugList.stream().map(drug -> DrugResponseDto.of(drug,drug.getDrugNutrientList().stream().map(drugNutrient -> { return drugNutrient.getStandardNutrient().getName(); }).collect(Collectors.toList()))).collect(Collectors.toList());원래 안된다면 성능 1대다 상황에서 성능 최적화는 어떻게 진행하는지 궁금하네요!
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
JPA Transaction에서 Delete 되지 않는 현상 관련
@Entity @Getter @Setter @Table(name = "user") @NoArgsConstructor public class User extends TimeStamp { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; @Column(nullable = false, unique = true) private String email; @Column(nullable = false) private String password; @Column(nullable = false, unique = true) private String phone; @Column(nullable = false) private String address; @Column(nullable = false, length = 36) private String emailVerificationToken; @Column(nullable = false) private LocalDateTime emailVerificationExpiresAt = LocalDateTime.now().plusHours(24); @Column(nullable = false) private Boolean emailVerifiedStatus = false; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) private List<WishList> wishes; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) private List<Cart> carts; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) private List<OrderList> orderList; public User( String name, String email, String password, String phone, String address, String emailVerificationToken, Boolean emailVerifiedStatus ) { this.name = name; this.email = email; this.password = password; this.phone = phone; this.address = address; this.emailVerificationToken = emailVerificationToken; this.emailVerifiedStatus = emailVerifiedStatus; } }@Service @RequiredArgsConstructor public class CartService { private final UserRepository userRepository; private final ProductRepository productRepository; private final CartRepository cartRepository; public List<CartResponseDto> getCartList(Long userId) { User user = findByuser(userId); List<Cart> cartLists = user.getCarts(); return cartLists.stream() .map(cartList -> new CartResponseDto( cartList.getProduct().getId(), cartList.getProduct().getName(), cartList.getQuantity(), cartList.getProduct().getPrice() * cartList.getQuantity(), cartList.getProduct().getProductStock().getStockQuantity()) ).toList(); } // 장바구니 삭제 @Transactional public List<CartResponseDto> cartDelete(Long userId, CartRequestDto cartRequestDto) { cartRepository.deleteByUserIdAndProductId(userId, cartRequestDto.getProductId()); return getCartList(userId); } private User findByuser(Long userId) { return userRepository.findById(userId).get(); } }@Repository public interface CartRepository extends JpaRepository<Cart, Long> { void deleteByUserIdAndProductId(Long userId, Long productId); }User Entity에 cart 테이블 연관관계를 맺고orderService에서 cartRepository.deleteByUserIdAndProductId에서 데이터를 삭제 후 getCartList를 조회해 retrun 하려고 합니다.예) cart tableid user_id product_id quantity1 41 6 12 41 7 13 41 11 1이때 cartRepository.deleteByUserIdAndProductId에서 product_id 6번을 삭제하고 getCartList를 조회하였는데 6번에 삭제되지 않고 6,7,11이 전부 조회 되었습니다.삭제되지 않는 이유가 무었일까요 ? Hibernate: select u1_0.id,u1_0.address,u1_0.created_at,u1_0.email,u1_0.email_verification_expires_at,u1_0.email_verification_token,u1_0.email_verified_status,u1_0.name,u1_0.password,u1_0.phone,u1_0.updated_at from user u1_0 where u1_0.email=? Hibernate: select c1_0.id,c1_0.product_id,c1_0.quantity,c1_0.user_id from cart c1_0 where c1_0.user_id=? and c1_0.product_id=? Hibernate: select p1_0.id,p1_0.best_status,p1_0.created_at,p1_0.description,p1_0.description_image,p1_0.name,p1_0.new_status,p1_0.price,p1_0.sold_out_status,p1_0.thumbnail_image,p1_0.updated_at from product p1_0 where p1_0.id=? Hibernate: select ps1_0.id,p1_0.id,p1_0.best_status,p1_0.created_at,p1_0.description,p1_0.description_image,p1_0.name,p1_0.new_status,p1_0.price,p1_0.sold_out_status,p1_0.thumbnail_image,p1_0.updated_at,ps1_0.stock_quantity from product_stock_quantity ps1_0 left join product p1_0 on p1_0.id=ps1_0.product_id where ps1_0.product_id=? Hibernate: select u1_0.id,u1_0.address,u1_0.created_at,u1_0.email,u1_0.email_verification_expires_at,u1_0.email_verification_token,u1_0.email_verified_status,u1_0.name,u1_0.password,u1_0.phone,u1_0.updated_at from user u1_0 where u1_0.id=? Hibernate: select c1_0.user_id,c1_0.id,c1_0.product_id,p1_0.id,p1_0.best_status,p1_0.created_at,p1_0.description,p1_0.description_image,p1_0.name,p1_0.new_status,p1_0.price,p1_0.sold_out_status,p1_0.thumbnail_image,p1_0.updated_at,c1_0.quantity from cart c1_0 left join product p1_0 on p1_0.id=c1_0.product_id where c1_0.user_id=? Hibernate: select ps1_0.id,p1_0.id,p1_0.best_status,p1_0.created_at,p1_0.description,p1_0.description_image,p1_0.name,p1_0.new_status,p1_0.price,p1_0.sold_out_status,p1_0.thumbnail_image,p1_0.updated_at,ps1_0.stock_quantity from product_stock_quantity ps1_0 left join product p1_0 on p1_0.id=ps1_0.product_id where ps1_0.product_id=? Hibernate: select ps1_0.id,p1_0.id,p1_0.best_status,p1_0.created_at,p1_0.description,p1_0.description_image,p1_0.name,p1_0.new_status,p1_0.price,p1_0.sold_out_status,p1_0.thumbnail_image,p1_0.updated_at,ps1_0.stock_quantity from product_stock_quantity ps1_0 left join product p1_0 on p1_0.id=ps1_0.product_id where ps1_0.product_id=?
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
H2 DB 관련 문의입니다.
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요. 이번에 JPA를 시작하는 학생입니다.H2 DB 실행시 계속 연결할 수 없다고 나오는데 혹시 해결 방법을 알 수 있을까요? 화면 첨부합니다현재 네이버 웨일 브라우저를 사용하고 있는데 크롬에서도 동일 현상이 발생했습니다.감사합니다.
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
값 타입 컬렉션 정말 쓰면 안되나요??
안녕하세요 영한님! 질문이있어서 찾아왔습니다. 현재 프로젝트를 진행중인데 한줄로 요약하면 기준 영양 성분에 맞추어 부족,과잉 영양분을 판별해 주는 프로젝트입니다. 저는 기준 영양성분을 ENUM 타입으로 관리하자는 입장이였습니다. 그 이유는 1) 저희 서비스는 적정영양성분 부족과잉을 판별 하는데 매번 DB를 조회해서 findProperAmountByName("단백질") 을 매번 같은 적정량을 조회하는 게 부담스럽다. => Enum 타입으로 탄수화물의 적정량을 넣어두면 훨씬 편하게 조회할 수 있을 것이다.2) findProperAmountByName("단백질") 은 현재 코드만으로는 DB에 어떤 영양소가 있는지도 모르고 확인하기 어렵다. ENUM 타입으로 묶으면 CARBON_HYDRATE,PROTEIN 등등 이렇게 묶어서 편하게 관리할 수 있다. 이렇게 생각하고 또 개발을 진행중에 있었습니다. 그러던 와중에 "영양제" 라는 컨텐츠에 탄수화물, 단백질 이 부족할 때 좋은 영양제라는 의미로 "탄수화물","단백질" 이라는 키워드를 쓰고 싶을 때 <아래는 영양제 칼럼>@ElementCollection(targetClass = StandardNutrient.class) @JoinTable(name = "StandardNutrient",joinColumns = @JoinColumn(name = "drug_id")) @Column(name ="StandardNutrientName", nullable = false) @Enumerated(EnumType.STRING) private Set<StandardNutrient> efficientNutrient = new HashSet<>();이렇게 쓰고 싶은 마음이 굴둑 같습니다. 이렇게 했을 때 발생할 수 있는 단점에 대해 알고 싶습니다. (StandardNutrient는 Enum 타입입니다. )1) 일단 StandareNutrient 의 종류가 바뀔일이 절대 없습니다!2) 이 서비스의 Manager 만 영양제를 등록할 수 있습니다. 3) List 대신 Set 을 사용함으로써 다 delete 한이후 insert 하지도 않습니다. 어떻게 생각하시나요?
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
영속성 컨텍스트 프록시 오류 질문
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)컨트롤러@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @PreAuthorize("isAuthenticated()") public ResponseEntity<Long> createWalkInvitation( @RequestPart("walkInvitaionCreateRequestDto") WalkInvitaionCreateRequestDto request, @RequestPart("uploadPhotos") MultipartFile[] multipartFiles, @AuthenticationPrincipal PrincipalDetails principalDetails){ Long savedId = walkInvitationService.createWalkInvitation(request, multipartFiles, principalDetails); return ResponseEntity.ok().body(savedId); }서비스 계층 public Long createWalkInvitation(WalkInvitaionCreateRequestDto request, MultipartFile[] multipartFiles, PrincipalDetails principalDetails) { Member member = principalDetails.getMember(); WalkInvitation walkInvitation = WalkInvitation.builder() .writer(member) .title(request.getTitle()) .content(request.getContent()) .latitude(request.getLatitude()) .longitude(request.getLongitude()) .detailedLocation(request.getDetailedLocation()) .walkStartDateTime(request.getWalkStartDateTime()) .walkingStatus("산책 대기 중") .build(); // member.getWalkInvitations().add(walkInvitation); List<Photo> photos = photoService.savePhotosToWalkInvitation(multipartFiles, walkInvitation); walkInvitation.addPhotos(photos); walkInvitationRepository.save(walkInvitation); return walkInvitation.getId();위 주석처리 한 부분// member.getWalkInvitations().add(walkInvitation)에서 failed to lazily initialize a collection of role가 발생합니다.오류가 발생하는 이유는 JWT 토큰 방식을 구현한 스프핑 시큐리티의 인증/인가 과정에서 해당 컨트롤러에 도달하기전에 필터에서 이미 SecurityContext에 principalDetails를 authentication 하면서 principalDetails라는 객체에 member가 저장되어 있는 상태입니다.그래서 이미 서비스 계층에서 위 코드에 Member member = principalDetails.getMember();를 호출하는 시점에는 getMember 호출 시 DB에 접근해서 값을 가져오는 것이 아닌, 순수한 객체 상태의 member를 가져오기 때문에 영속성 컨텍스트에 member가 저장되어 있지 않기에 프록시 오류가 발생하는 것 같습니다(로그로 DB에 접근하지 않는 것 확인) 이러한 문제를 해결하기 위해서는 principalDetails.getMember()로 얻은 멤버정보로 DB에 저장된 Member를 다시 가져와서 영속성 컨텍스트에 저장시키는 방식을 택해야 할까요?스프핑 시큐리티의 인증/인가 과정(JwtAuthorizationFilter)에서 accesstoken을 바탕으로 이미 member를 db에서 찾아오는 쿼리문이 한번 나갔는데, 또 호출하려니 조금 비효율적인 것 같아서 고민이 됩니다. 다른 방법이 있을까요?
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
em.close()는 왜 준영속 상태인가요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]강의 범위자바 ORM 표준 JPA 프로그래밍 - 기본편 섹션3. 영속성 관리 - 내부 동작 방식 준영속 상태 질문 내용6:14 에서 em.close()가 준영속 상태라고 하셨는데영속성 컨텍스트가 종료되면영속성 컨텍스트 자체가 없는거잖아요 그러면 준영속이 아니라최초의즉, new 로 객체 생성만 한 비영속 상태가 되어야 하는게 아닌가요? 왜 close()를 하면 준영속 상태가 되는 건지 궁금합니다.
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
JPA
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]@Table 설정하면 insert문이 나가면서 jpa 실행 시간에 영향을 준다고 하셨는데 insert문 없이 create만 나가서요 이것도 jpa 실행 시간에 영향을 안주는 거 아닌가요??
- 해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
from절의 서브쿼리 테스트 문제
[질문 내용]하이버네이트 6에서 from절의 서브 쿼리 테스트 위해 다음과 같은 쿼리를 작성해서 실행 했는데, 쿼리가 날아가지 않습니다. 잘못된 부분이 있을까요?
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
상속관계 Joined - 임시 테이블로 생성/삭제로 인한 성능 문제
안녕하세요 영한님.상속관계 Joined 매핑을 사용할 때, 부모테이블에 대하여 업데이트 쿼리 시 임시 테이블 Create Drop 에 대해 질문드리고 싶습니다. 최근에 플젝을 진행하면서 JPA 상속관계 Joined 전략을 활용했는데요, 프로젝트 초기에는 정규화된 테이블 구조로 먼저 진행하고, 추후 성능 이슈가 발생하면 단일 테이블 전략으로 역 정규화를 논의하는 것이 나을 것으로 판단했기 때문입니다.Domain// 부모 엔티티 @Entity @DiscriminatorColumn @Inheritance(strategy = InheritanceType.JOINED) public class Notification { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "notification_id") private Long id; @Enumerated(value = EnumType.STRING) @Column(nullable = false, columnDefinition = "varchar(50)") private NotificationEventType notificationEventType; @Column(nullable = false) private LocalDateTime createdAt; @Column(name = "\"read\"", nullable = false) private Boolean read; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", nullable = false) private User notifier; }// 자식 엔티티 @Entity public class RecruitmentNotification extends Notification { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "recruitment_id", nullable = false) private Recruitment actor; } @Entity public class StudyNotification extends Notification { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "study_id", nullable = false) private Study actor; } @Entity public class ReviewNotification extends Notification { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "review_id", nullable = false) private Review actor; } Service@Service @RequiredArgsConstructor @Slf4j public class NotificationCommandService { private final NotificationRepositoryImpl notificationRepository; public void updateNotificationsAsRead(final User user, final List<Long> notificationIds) { notificationRepository.updateNotificationsAsRead(user.getId(), notificationIds); } } Repositorypublic interface NotificationJpaRepository extends JpaRepository<Notification, Long> { @Modifying @Query("UPDATE Notification n " + "SET n.read = true " + "WHERE n.notifier.id = :userId AND n.id IN :notificationIds") void updateNotificationsAsRead(final Long userId, final List<Long> notificationIds); } @Repository @RequiredArgsConstructor public class NotificationRepositoryImpl { private final JPAQueryFactory q; private final NotificationJpaRepository notificationJpaRepository; private final EntityManager em; public void updateNotificationsAsRead(final Long userId, final List<Long> notificationIds) { notificationJpaRepository.updateNotificationsAsRead(userId, notificationIds); em.flush(); em.clear(); } } 부모테이블에 대하여 업데이트 쿼리 시, JPA 구현체가 자체적으로 임시 테이블을 Create 및 Drop 하는 로그를 확인했습니다.create temporary table if not exists HT_notification(notification_id bigint not null, primary key (notification_id)) drop temporary table HT_notification 두 가지 문제점이 있다고 생각하는데요.보안 이슈 등을 고려하여, 현재 상용 DB 의 백엔드 사용자 권한에 DDL을 제외하였습니다.이에 따라 임시 테이블을 생성하지 못하고, 500 에러가 발생하는 상황입니다.JPA 상속 관계 매핑 전략만을 위해 DB 사용자 권한을 넓게 가져가는 것이 올바른지 잘 모르겠습니다 🤔 업데이트 API를 호출할 때마다, 임시 테이블을 생성하고 드랍하는 행위가 매우 비효율적이라 생각되는데,이럴 경우 Single 테이블 전략으로 수정하거나, 상속관계 매핑 자체를 안쓰는 방법밖엔 없을까요?상속관계 매핑 전략은 애플리케이션 레벨에서 DB 테이블의 조작을 손쉽게하는 장점이 있긴하지만,결국 상용 서비스 중인 DB를 세팅할 땐 데이터베이스 레벨에서 DDL을 직접 세팅하는게 좋고, 기존의 장점이 상쇄되는 느낌입니다.성능적 손해를 감수하면서도 상속 관계 매핑을 활용하는게 좋은 접근 방법인지 판단이 서지 않아 질문드립니다 🙂
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
상속관계 Joined 매핑 - 임시 테이블 Create Drop에 관하여
안녕하세요 영한님.상속관계 Joined 매핑을 사용할 때, 부모테이블에 대하여 업데이트 쿼리 시 임시 테이블 Create Drop 에 대해 질문드리고 싶습니다. 최근에 플젝을 진행하면서 JPA 상속관계 Joined 전략을 활용했습니다.부모테이블에 대하여 업데이트 쿼리 시, JPA 구현체가 자체적으로 임시 테이블을 Create 및 Drop 하는 로그를 확인했습니다. Domain// 부모 엔티티 @Entity @DiscriminatorColumn @Inheritance(strategy = InheritanceType.JOINED) public class Notification { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "notification_id") private Long id; @Enumerated(value = EnumType.STRING) @Column(nullable = false, columnDefinition = "varchar(50)") private NotificationEventType notificationEventType; @Column(nullable = false) private LocalDateTime createdAt; @Column(name = "\"read\"", nullable = false) private Boolean read; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", nullable = false) private User notifier; }// 자식 엔티티 @Entity public class RecruitmentNotification extends Notification { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "recruitment_id", nullable = false) private Recruitment actor; } @Entity public class StudyNotification extends Notification { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "study_id", nullable = false) private Study actor; } @Entity public class ReviewNotification extends Notification { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "review_id", nullable = false) private Review actor; } Service@Service @RequiredArgsConstructor @Slf4j public class NotificationCommandService { private final NotificationRepositoryImpl notificationRepository; public void updateNotificationsAsRead(final User user, final List<Long> notificationIds) { notificationRepository.updateNotificationsAsRead(user.getId(), notificationIds); } } Repositorypublic interface NotificationJpaRepository extends JpaRepository<Notification, Long> { @Modifying @Query("UPDATE Notification n " + "SET n.read = true " + "WHERE n.notifier.id = :userId AND n.id IN :notificationIds") void updateNotificationsAsRead(final Long userId, final List<Long> notificationIds); } @Repository @RequiredArgsConstructor public class NotificationRepositoryImpl { private final JPAQueryFactory q; private final NotificationJpaRepository notificationJpaRepository; private final EntityManager em; public void updateNotificationsAsRead(final Long userId, final List<Long> notificationIds) { notificationJpaRepository.updateNotificationsAsRead(userId, notificationIds); em.flush(); em.clear(); } } 업데이트 API를 호출할 때마다, 임시 테이블을 생성하고 드랍하는 행위가 매우 비효율적이라 생각되는데,이럴 경우 Single 테이블 전략으로 수정하거나, 상속관계 매핑 자체를 안쓰는 방법밖엔 없을까요? 상속관계 매핑 전략은 애플리케이션 레벨에서 DB 테이블의 조작을 손쉽게하는 장점이 있긴하지만,결국 상용 서비스 중인 DB를 세팅할 땐 데이터베이스 레벨에서 DDL을 직접 세팅하는게 좋고, 기존의 장점이 상쇄되는 느낌입니다.성능적 손해를 감수하면서도 상속 관계 매핑을 활용하는게 좋은 접근 방법인지 판단이 서지 않아 질문드립니다 🙂
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
여러 서버에서 db 접근 시 동시성문제
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]여러 서버에서 db에 접근할 경우 sequence전략의 인덱스 처리가 궁금합니다.allocationsize를 50으로 설정한 경우a 서버에서 1~50까지 확보, 다음 인덱스번호 51번(a서버에서 아직 종료되지 않음)b 서버에서 인덱스번호 요청 51번 반환, 51~100번 인덱스 사용만약 해당 상황의 a서버에서 데이터를 3개 추가한 후 종료된다면 1,2,3번 인덱스만 사용되고 4~50번 인덱스는 앞으로 사용되지 않는건가요??그리고 여러 서버를 작동시키고 이러한 방식으로 사용한다면 중간중간 비어있는 인덱스가 많아질 것인데, 비어있는 인덱스는 재활용이 불가능한지 궁금합니다.
- 해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
기본값 타입에 식별자도 포함되는지
JPA에서는 데이터 타입을 톱레벨에서 2가지, 엔티티 타입과 값 타입으로 분류한다고 하는데 식별자도 값 타입 중 기본값 타입으로 분류되는 것이 맞나요? 예를 들어 Member 엔티티에 식별자인 memberId와 필드인 name, age가 있다면memberId, name, age 모두 기본값 타입인 것인지 궁급합니다. 당연한 질문일 수도 있겠지만, 설명하실 때와 강의자료에서 모두 식별자가 기본값 타입이라는 언급을 안하시는 것 같아서 예외적인 부분인가 하여 질문합니다.
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
회원 상속전략
안녕하세요 일정 부분을 공유하는 회원 엔티티를 설계할 때의 상속전략 vs 분리가 궁금합니다.민원인, 직원 이렇게 2종류가 있고 아이디, 비밀번호, 사번 등이 동일하고 직원은 여기서 몇개만 추가된다고 가정한다면엔티티를 따로 분리하는게 아닌 공통속성 엔티티를 상속해서 만들어도 괜찮을까요?몇일을 고민해도 답이 쉽게 나오지 않네요ㅜㅜ
- 해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
단일 테이블 전략 조회 성능 임계점
단일 테이블 전략에서 단일 테이블에 모든 것을 저장하기 때문에 테이블이 비대해지고, 이에 따라 조회 성능에 문제가 발생할 수 있다고 하는데임계점을 넘는 경우에만 그렇다 라고 말씀하십니다.일반적으로 임계점은 어느정도인지 궁금합니다.
- 해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
h2 데이터베이스 설정 질문 드립니다.
안녕하세요 다른 강의랑 병행하며 들으려고 하는중입니다! 다른 강의도 h2 데이터베이스를 사용하는데 , h2 데이터베이스를 두 강의에서 각각 사용하려면 어떻게 설정해야할지 모르겠습니다. 알려주시면 감사드리겠습니다.
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
@BatchSize 적용 시 로그
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요. 정말 JPA를 제대로 배우며 유익한 시간을 보내고 있는 수강생입니다.질문 1.페치조인2 - 한계 강의를 듣던 중 @BatchSize 를 조절하여N+1 문제를 해결하는 예시를 보여주시는데보여주신 예시의 로그와 제가 테스트 해봤을 때의 로그가 좀 다르게 나와 질문드립니다.인강에서 보여주실 때에는 load one-to-many 라고 주석이 달리면서 실제 조건문에서는 ? 가 2개만 찍혀있는데제가 테스트 해보니 BatchSize에 지정해준 숫자 만큼 로그에? 가 찍히는것을 확인 할 수 있었습니다.혹시 제가 잘 못 테스트 한 것 일까요?질문 2.또한 강의에서 일반적으로 BatchSize 를 전역 설정으로 해놓고 100~1000 사이의 크기를 지정하여 사용하신다고 말씀하셨는데 이는 DB 조회 쿼리 횟수는 줄어들어 N+1 문제는 완화할수 있지만 지연 로딩 시 내가 접근한 객체의 수 만큼만 로드하는 것이 아닌 무조건 배치 사이즈 만큼 로드되기 때문에그 간격이 크면 메모리적인 낭비가 되는거 아닌가요?
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
TABLE_PER_CLASS 전략 단점관련 질문있습니다
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 안녕하세요 강의 정말 잘 듣고있습니다 !!강의 30:00 부근에서 TABLE_PER_CLASS 전략이 왜 안좋냐면 조회시 부모 클래스로 조회를 할 수도 있는데 그런경우에 UNION 쿼리가 나가는 단점이 있다고 하셨습니다.그래서 전략을 JOINED로 바꾸고 실행해봤는데 이런식으로 LEFT JOIN을 여러번 하게 되고SINGLE TABLE 전략은 예상한대로 이런 결과가 나오더라구요. 이 결과들만 보면 SINGLE TABLE이 말씀하신것처럼 심플하게 조회가 되고,JOINED와 TABLE PER CLASS 는 사실 성능상 비슷해보이는데TABLE PER CLASS 전략만 단점을 소개해주셔서 질문드렸습니다.질문은 한마디로, JOINED도 성능이 그렇게 좋진 않은것 아닌가??입니다!! 읽어주셔서 감사합니다.
- 미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
쓰기지연과 조회
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요? 몇가지 이것저것 테스트하다 발견한 부분에 대해 의문이 들어서 질문드립니다.,insert, update, delete 등 Write와 관련된 작업은 쓰기지연 저장소에 저장되고, commit될 때 flush가 된다고 이해했는데요때때로 select가 수행되었을 때 Write관련 쿼리가 수행되는 것 같더라구요Delete A엔티티 -> Delete B엔티티 -> select C -> select D 엔티티 -> commit순으로 진행된다고 할 때, delete A, delete B 는 commit되면서 쿼리가 실행되어야 할 것 같은데, select C 시점에 쿼리가 실행되는 것 같은데(즉 select C 시점에 flush가 되는 것 같은데), 제가 추론한 게 맞는지, 왜 그런건지 이유가 궁금합니다감사합니다!