Cascade (영속성 전이)
- 다대일에서 일쪽에 즉, 부모에 걸어야 함(게시물과 댓글 중 게시물에)
- 양쪽 엔티티의 라이프사이클이 동일하거나 비슷할 때 거는 것
- 영속성 전이는 현재 엔티티에서만 전이되야 함 → 댓글을 게시물이 아닌 다른 곳에서 하면 안 됨
- 옵션 종류
- ALL : 전체 상태 전이
- PERSIST : 저장 상태 전이
- REMOVE : 삭제 상태 전이
- MERGE : 업데이트 상태 전이
- REFERESH : 갱신 상태 전이
- DETACH : 비영속성 상태 전이
예를 들어 Cascade.REMOVE를 하면 게시물이 삭제됐을 때 댓글도 삭제됨
@Entity
public class Parent {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
private List<Child> children = new ArrayList<>();
public void addChild(Child child) {
children.add(child);
child.setParent(this);
}
}
@Entity
public class Child {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
}
// 사용 예
Parent parent = new Parent();
parent.setName("부모 엔티티");
Child child1 = new Child();
child1.setName("자식1");
Child child2 = new Child();
child2.setName("자식2");
parent.addChild(child1);
parent.addChild(child2);
@Service
@RequiredArgsConstructor
public class PostService {
private final PostRepository postRepository;
private final CommentRepository commentRepository;
@Transactional
public void addComment(Long postId, String content) {
// 게시글 조회
Post post = postRepository.findById(postId)
.orElseThrow(() -> new EntityNotFoundException("게시글을 찾을 수 없습니다."));
// 댓글 생성
Comment comment = new Comment(content);
post.addComment(comment); // Post 엔티티의 addComment 메서드 호출
// 저장 (CascadeType.ALL 덕분에 post 저장 시 comment도 저장됨)
postRepository.save(post);
}
}
-> Parent를 DB에 저장하면, List<Child>에 있는 Child들도 DB에 저장
orphanRemoval (고아 객체 제거)
- 다대일에서 일쪽에 즉, 부모에 걸어야 함(게시물과 댓글 중 게시물에)
- Cascade.REMOVE 와 비슷한 용도로 삭제를 전파하는데 쓰임
- 부모객체가 삭제됐을 때 자식이 삭제되고, 부모 객체의 리스트에서 해당 자식객체의 요소를 삭제한 경우에도 자식이 삭제됨
- 리스트 요소로써의 영속성 전이도 해준다는 뜻
- 옵션
- true
- false
parent1.getChildList().remove(0); // delete 쿼리가 나감
영속성 전이 최강 조합 : orphanRemoval=true + Cascade.ALL
→ 자식 엔티티의 라이프 사이클이 부모 엔티티와 동일해지며, 직접 자식 엔티티의 생명주기를 관리할 수 있음
Fetch (조회시점)
- @ManyToMany, @OneToMany, @ManyToOne, @OneToOne에 사용
- 기본 LAZY(부모 조회 시 자식은 필요할 때 조회) 를 설정한 뒤에 필요할때만 fetch Join 을 수행
- 같이 쓰이는 연관관계 일 경우만 EAGER(부모 조회 시 자식도 같이 조회) 를 설정
JpaRepository 효율적으로 사용하는 방법
Optional 제거하기 : 비지니스 로직에서 Optional 처리를 위한 추가적인 작업을 방지
public interface UserRepository extends JpaRepository<User, Long> {
// Default 메소드를 사용하여 findById의 Optional을 내부적으로 처리
default User findUserById(Long id) {
return findById(id).orElseThrow(() -> new DataNotFoundException("User not found with id: " + id));
}
}
메서드명 간소화하기 : default 메서드를 활용하면 긴 메서드명을 간결하고 명확하게 표현
public interface ProductRepository extends JpaRepository<Product, Long> {
// 기존의 긴 쿼리 메소드
List<Product> findAllByCategoryAndPriceGreaterThanEqualAndPriceLessThanEqualOrderByPriceAsc(String category, BigDecimal minPrice, BigDecimal maxPrice);
// Default 메소드를 사용하여 간결한 메소드명 제공
default List<Product> findProductsByCategoryAndPriceRange(String category, BigDecimal minPrice, BigDecimal maxPrice) {
return findAllByCategoryAndPriceGreaterThanEqualAndPriceLessThanEqualOrderByPriceAsc(category, minPrice, maxPrice);
}
}
테이블 객체로 페이지 조회하기
페이징 처리 프로세스
- PageRequest 를 사용하여 Pageable에 페이징 정보를 담아 객체화
- Pageable을 JpaRepository가 상속된 인터페이스의 메서드에 T(Entity)와 함꼐 파라미터로 전달
- 2번의 메서드의 return 으로 Page<T>가 응답
- 응답된 Page<T>에 담겨진 Page 정보를 바탕으로 로직을 처리
페이징 정렬
Sort 클래스
Sort sort1 = Sort.by("name").descending(); // 내림차순
Sort sort2 = Sort.by("password").ascending(); // 오름차순
Sort sortAll = sort1.and(sort2); // 2개이상 다중정렬도 가능하다
Pageable pageable = PageRequest.of(0, 10, sortAll); // pageable 생성시 추가
@Query 사용시 Alias(쿼리에서 as 로 지정한 문구) 를 기준으로 정렬
// 아래와 같이 AS user_password 로 Alias(AS) 를 걸어주면
@Query("SELECT u.user_name, u.password AS user_password FROM user u WHERE u.username = ?1")
List<User> findByUsername(String username, Sort sort);
// 이렇게 해당 user_password 를 기준으로 정렬할 수 있다.
List<User> users = findByUsername("user", Sort.by("user_password"));
JPA 속도 향상하는 방법 : 필요한 부분만 갱신하기
@DynamicInsert
Insert 쿼리를 날릴 때 null 인 값은 제외하고 쿼리문이 만들어짐
Hibernate:
insert
into
users
(username, id)
values
(?, ?) // 133ms 소요
@DynamicUpdate
Update 쿼리를 날릴 때 null인 값은 제외하고 쿼리문이 만들어짐
Hibernate:
update
users
set
password=?
where
id=? // 134ms
-> 필드가 많아질수록 둘 다 속도가 향상된다!
'Spring' 카테고리의 다른 글
User 데이터 100만건 생성하고 성능 개선하기 (1) | 2025.03.21 |
---|---|
intellij 프로젝트 내부에 작업물이 안 보일 때 해결방법 (0) | 2025.03.12 |
영속성(persist,merge..)과 쓰기지연 (0) | 2025.03.11 |
데이터베이스 Driver와 JDBC (1) | 2025.03.11 |
장바구니 및 주문 기능 구현하기 (0) | 2025.03.06 |