JPA 프로그래밍 - 2 (스프링 데이터 JPA - 3)
1. Entity 상태
- Transient : JPA가 모르는 상태
- Persistent : JPA가 관리중인 상태 (1차 캐시, Dirty Checking, Write Behind, ...) - save
- Detached : JPA가 더이상 관리하지 않는 상태 - return 한 경우
- Removed : JPA가 관리하긴 하지만 삭제하기로 한 상태
save()를 호출한다고 바로 DB에 반영되는 것이 아님, JPA가 판단하여 DB에 반영
2. Cascade
엔티티의 상태 변화를 전파 시키는 옵션
Parent - Child 구조를 만들고 양방향 관계를 만듬
- Post.java
cascade를 통해 상태 변화시 저장된 Comment에게 전파하겠다는 설정을 함
@Entity
public class Post {
@Id @GeneratedValue
private Long id;
private String title;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
private Set<Comment> comments = new HashSet<>();
public void addComment(Comment comment) {
this.getComments().add(comment);
comment.setPost(this);
}
}
- Comment.java
@Entity
public class Comment {
@Id @GeneratedValue
private Long id;
private String comment;
@ManyToOne
private Post post;
}
- JpaRunner.java
Post가 save를 통해 Persistent 상태로 바뀌면, Comment 들도 상태가 바뀜 -> save를 하지 않은 comment들도 DB에 반영됨
@Component
@Transactional
public class JpaRunner implements ApplicationRunner {
@PersistenceContext
EntityManager entityManager;
@Override
public void run(ApplicationArguments args) throws Exception {
Post post = new Post();
post.setTitle("This is Title");
Comment comment = new Comment();
comment.setComment("comment");
post.addComment(comment);
Comment comment1 = new Comment();
comment1.setComment("comment1");
post.addComment(comment1);
Session session = entityManager.unwrap(Session.class);
session.save(post);
}
}
2. Fetch
연관 관계의 엔티티를 어떻게 가져올 것이냐.. 지금(Eager)? 나중에(Lazy)?
- @OneToMany의 기본값은 Lazy
- @ManyToOne의 기본값은 Eager (쿼리가 한 번 일어남)
*PK를 통한 쿼리에만 Fetch 모드가 결정됨
이를 잘 설정해야 성능을 최적화할 수 있음
필요 없는 값을 메모리에 너무 많이 올려놓으면 성능 문제 발생
3. Query
*항상 하이버네이트가 내가 의도한 쿼리를 하는지 살펴보기 - 의도하지 않는 쿼리는 성능 문제 발생 가능*
JPQL (HQL)
- SQL과 비슷하지만, 엔테티 기준으로 작성해야 함
- JPA 또는 하이버네이트가 해당 쿼리를 SQL로 변환해서 실행함
TypedQuery<Post> query = entityManager.createQuery("SELECT p From Post As p", Post.class);
List<Post> posts = query.getResultList();
posts.forEach(System.out::);
Criteria
- JPQL 은 타입 세이프 하지 않음! (문자열이 들어가기 때문에)
- 이는 타입 세이프 쿼리
Native Query
- SQL 쿼리 실행하기
List<Post> posts = entityManager.createNativeQuery("SELECT * FROM POST", Post.class).getResultList();
posts.forEach(System.out::println);
4. 성능 문제를 예방하기 위해 SQL문 확인하기
내가 예측한 대로 원하는 만큼 쿼리가 발생하는지?
원하는 데이터를 적절한 타이밍에 가져오고 있는지?
실행된 SQL문의 ? 값 확인하기
logging.level.org.hibernate.type.descriptor.sql=trace
인프런 백기선님 '스프링 데이터 JPA’ 강의를 듣고 정리한 내용입니다.