티스토리 뷰

개요

JPA가 사용하는 프록시와 지연로딩, 즉시로딩에 대하여 알아보고 영속성 전이에 대한 개념과 영속성 전이를 이용해 고아객체를 제거하는 방법에 대하여 이해한다.

 

프록시

엔티티가 실제 사용될 때까지 데이터베이스 조회를 지연하는 방법을 지연로딩 이라하고 이때 실제 엔티티 객체 대신 데이터베이스 조회를 지연할 수 있는 가짜 객체가 필요한데 이것을 프록시 객체라 한다.

@Getter
@Setter
@Entity
public class Game {
    @Id @GeneratedValue
    private Long id;

    private String name;
}

Game game = new Game();
game.setName("game");
em.persist(game);
        
em.flush(); em.clear();;

Game refGame = em.getEntityManager().getReference(Game.class, game.getId());
System.out.println(refGame.getClass().getName());
me.blog.jpa.model.proxy.Game$HibernateProxy$Quw3ynSC
  • EntityManaget.getReference()메소드를 사용해 실제 사용하는 시점까지 데이터베이스 조회를 미룰 수 있다.
  • 프록시의 특징
    • 프록시 객체는 처음 사용할 때 한번만 초기화 된다.
    • 프록시 객체를 초기화한다고 프록시 객체가 실제 엔티티로 바뀌는 것은 아니다. 프록시 객체가 초기화되면 프록시 객체를 통해서 실제 엔티티에 접근할 수 있다.
    • 프록시 객체는 원본 엔티티를 상속받은 객체이므로 타입 체크 시에 주의해서 사용해야 한다.
    • 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 데이터베이스를 조회할 필요가 없으므로 em.getReference()를 호출해도 프록시가 아닌 실제 엔티티를 반환한다.
    • 초기화는 영속성 컨텍스트의 도움을 받아야 가능하다. 따라서 준영속 상태의 프록시를 초기화하면 문제가 발생한다.

 

프록시 객체의 초기화

프록시 객체는 실제 사용될 때 데이터베이스를 조회해서 실제 엔티티 객체를 생성하는데 이것을 프록시 객체의 초기화라 한다.

Game game = new Game();
game.setName("game");
em.persist(game);

em.flush(); em.clear();;

Game refGame = em.getEntityManager().getReference(Game.class, game.getId());
System.out.println(refGame.getClass().getName());
System.out.println(refGame.getName()); // 해당 시점에 SELECT 실행
System.out.println(refGame.getClass().getName()); // proxy 그대로 사용

 

프록시 확인

PersistenceUnitUtil.isLoaded(Object Entity) 메소드를 사용하면 프록시 인스턴스의 초기화 여부를 확인 할 수 있다.

-> 책에서는 EntityManager에서 가져온다고 되어있는데 버전이 높아짐에따라 방식이 위의 메소드로 바꼈다고 한다!

 

즉시 로딩 - Eager Loading

  • 엔티티를 조회할 때 연관된 엔티티도 함께 조회한다.
  • @ManyToOne(FetchType.EARGER)의 형태로 사용
  • 즉시 로딩을 최적화하기 위해 가능하면 조인 쿼리를 사용한다. 
  • 조인 쿼리를 사용하여 즉시 로딩할 때 null을 허용하면 외부 조인, null을 허용하지 않으면 내부 조인을 실행한다.

 

지연 로딩 - Lazy Loading

  • 연관된 엔티티를 실제 사용할 때 조회한다.
  • @ManyToOne(fetch = FetchType.LAZY)의 형태로 사용
  • 엔티티를 조회할 때 연관된 엔티티가 영속성 컨텍스트에 없다면 프록시 객체로 조회하고 이 프록시 객체를 실제 사용할 때까지 데이터 로딩을 미룬다.

 

JPA 기본 페치 전략

  • @ManyToOne, @OneToOne : 즉시 로딩(FetchType.EAGER)
  • @OneToMany, @ManyToMany : 지연 로딩(FetchType.LAZY)

컬렉션을 하나 이상 즉시로딩하는 것은 권장하지 않는다. 

 

영속성 전이 : CASCADE

특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 사용

@Entity
public class Member {
	
    	@Id
        @Column(name = "member_id")
        private String id;
        
        private String userName;
        
        @ManyToOne
        @JoinColumn(name = "team_id")
        private Team team;
        
 }
@Entity
public class Team {
	
    @Id
    @Column(name = "team_id")
    private String id;
    
    private String name;
    
    @OneToMany(mappedBy = "team", cascade = CascadeType.PERSIST)
    private List<Member> memberList = new ArrayList<>();
 }
  • JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태여야 한다.
  • 영속성 전이를 사용하게 되면 부모만 영속 상태로 만들면 연관된 자식까지 한번에 영속 상태로 만들 수 있다.
  • ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH 옵션이 존재한다.

 

고아 객체

부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능

@Entity
public class Parent {

    @Id
    @GenerationValue
    private Long id;
    
    @OneToMany(mappedBy = "parent", orphanRemoval = true)
    private List<Child> children = new ArrayList<Child>();
    
}
  • 부모 엔티티의 컬렉션에서 자식 엔티티의 참조만 제거하면 자식 엔티티가 자동으로 삭제된다.
  • 컬렉션에서 제거하면 데이터베이스의 데이터도 삭제된다. 고아 객체 제거 기능은 영속성 컨텍스트를 플러시할 때 적용되므로 플러시 시점에 DELETE SQL이 실행된다.
  • 만약 삭제한 엔티티를 다른 곳에서도 참조한다면 문제가 발생할 수 있으므로 @OneToOne, @OneToMany에서만 사용할 수 있다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함