inblog logo
|
jjack1
    JavaSpring Boot

    [SB] 12. JPA

    최재원's avatar
    최재원
    Apr 13, 2025
    [SB] 12. JPA
    Contents
    1. Persistence Context1. PC의 위치2. PC의 기능2. Lazy Loading3. EAGER 과 LAZY4. 양방향 맵핑 @ManyToOne과 @OneToMany@ManyToOne (N:1 관계)@OneToMany (1:N 관계)양방향 관계 정리양방향 맵핑을 하면 좋은 점⚠️ 주의사항5. Cascade
    1. createNativeQuery
        • 기본 SQL 쿼리를 실행할 때 사용
    1. createQuery
        • JPA가 제공하는 객체지향 쿼리를 실행할 때 사용
        • 예시: select b from Board b join fetch b.user u left join fetch b.replies r left join fetch r.user where b.id = :id order by r.id desc
          • board_tb → Board 객체
          • b → 별칭
          • ? → :username
          • inner join → join fetch
          • on → b.user
          • left outer join → left join
    1. createNamedQuery
        • Query Method
        • 함수 이름으로 쿼리를 생성
        • 사용하지 않음
    1. createEntityGraph
        • 사용하지 않음
    1. createEntityGraph
        • 사용하지 않음
    1. persist
        • 객체를 영속화 시킴
        • id 가 없는 객체는 insert 함
    1. find
        • 영속화 된 객체를 가져옴
        • 없으면 select 해서 가져옴

    1. Persistence Context

    1. PC의 위치

    notion image

    2. PC의 기능

    notion image
    1. User user = joinDTO.toEntity(); // 1. 비영속 객체
      1. notion image
    1. em.persist(user); // 2. user -> 영속 객체
    1. insert
      1. notion image
    1. System.out.println(user); // 3. user -> db와 동기화
      1. notion image
     

    2. Lazy Loading

    엔티티 내부 연관관계의 객체를 초기에 로딩(조회, select)하지 않고, 연관관계에 있는 객체의 필드값에 접근 할 때 로딩되는 것
    public class Board { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String title; private String content; private Boolean isPublic; @ManyToOne(fetch = FetchType.LAZY) private User user; private Timestamp createdAt; }
    • Board 객체를 조회할 때 User 객체는 로딩되지 않는다
    • Board 객체에서 User 객체의 필드 값에 접근할 때 User 객체가 로딩된다

    핵심 요약

    • 레이지 로딩 주체: Hibernate (JPA 구현체)
    • 방법: 프록시 객체 생성 → 실제 접근 시점에 쿼리 실행
    • 주의: 영속성 컨텍스트가 닫힌 후(@Transactional 바깥 등)에 접근하면 LazyInitializationException 발생

    3. EAGER 과 LAZY

    • EAGER → 연관된 객체의 데이터를 바로 받고 싶을 때
    • LAZY → 받기 싫고 나중에 getter 를 호출할 때만 데이터를 받고 싶을 때
     

    4. 양방향 맵핑 @ManyToOne과 @OneToMany

    @ManyToOne 과 @OneToMany 가 서로 걸려있는 경우를 양방향 맵핑이라 한다

    @ManyToOne (N:1 관계)

    • 다수(N)의 엔티티가 하나(1)의 엔티티에 연결되어 있을 때 사용.
    • 보통 외래 키는 @ManyToOne 쪽에 존재.
    • 예: 여러 Reply 는 하나의 Board 에 속함.
    public class Reply { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @ManyToOne(fetch = FetchType.LAZY) private User user; @ManyToOne(fetch = FetchType.LAZY) private Board board; private String content; // 댓글 내용 @CreationTimestamp private Timestamp createdAt; }

    @OneToMany (1:N 관계)

    • 하나(1)의 엔티티가 여러 개(N)의 엔티티를 가짐.
    • 외래 키는 반대편(@ManyToOne)에 있으므로, mappedBy 속성 필요.
    • 주 테이블에는 외래 키가 없고, 연관된 객체 컬렉션만 존재.
    public class Board { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String title; private String content; private Boolean isPublic; @ManyToOne(fetch = FetchType.LAZY) // 연관관계 설정 -> ORM 하려고 EAGER -> fk에 들어간 오브젝트를 바로 연관관계 맵핑을 해서 select를 여러 번 한다 , LAZY -> 무조건 LAZY를 사용한다. 연관관계 맵핑을 하지 않는다 private User user; @OneToMany(mappedBy = "board", fetch = FetchType.LAZY, cascade = CascadeType.ALL) // mappedBy -> fk 의 주인인 reply의 필드 이름을 적어야 한다 private List<Reply> replies = new ArrayList<Reply>(); @CreationTimestamp private Timestamp createdA }

    양방향 관계 정리

    // Board <--> Reply // Board: 1개 // Reply: 여러 개
    • Reply 에서는 @ManyToOne 으로 Board 를 참조
    • Board 에서는 @OneToMany(mappedBy = "board") 로 컬렉션으로 Reply 를 참조
      • mappedBy 로 지정하는 이름은 Reply 에서 @ManyToOne 로 지정한 변수 이름을 넣는 것이다

    양방향 맵핑을 하면 좋은 점

    • 이렇게 쿼리를 작성하면
    em.createQuery("select b from Board b join fetch b.user u left join fetch b.replies r where b.id = :id", Board.class);
    • 이렇게 자동으로 오브젝트 릴레이션 맵핑을 하기 때문
      • notion image

    ⚠️ 주의사항

    1. 연관관계의 주인(owner)

    • @ManyToOne 쪽이 연관관계의 주인 (즉, DB에 외래 키를 갖고 있음)
    • @OneToMany는 mappedBy로 주인을 지정할 뿐, 외래 키를 소유하지 않음

    2. 양방향 관계 설정 시 무한 루프 주의 (toString, JSON 직렬화)

    • 예: @ToString.Exclude, @JsonManagedReference, @JsonBackReference 등 사용

    5. Cascade

    notion image

    @oneToMany

    위 어노테이션을 가지고 있는 List<Reply> replies 객체는 여기에 Reply 가 추가 되거나 삭제 되면 트랜잭션이 끝난 다음 insert or delete 쿼리가 작동한다
    쿼리를 진짜 객체 지향적으로 사용하는 방법
     
    Share article
    Contents
    1. Persistence Context1. PC의 위치2. PC의 기능2. Lazy Loading3. EAGER 과 LAZY4. 양방향 맵핑 @ManyToOne과 @OneToMany@ManyToOne (N:1 관계)@OneToMany (1:N 관계)양방향 관계 정리양방향 맵핑을 하면 좋은 점⚠️ 주의사항5. Cascade

    jjack1

    RSS·Powered by Inblog