2026.04.21
부모 엔티티의 영속성 상태 변화를 자식 엔티티에게 그대로 전파하는 기능
CascadeType.ALL : 모든 Cascade옵션을 적용 (부모와 자식의 생명주기가 완벽하게 일치할 때 사용)CascadeType.PERSIST : 부모 엔티티를 저장할 때, 연관된 자식 엔티티도 함께 저장CascadeType.REMOVE : 부모 엔티티를 삭제 할 때, 연관된 자식 엔티티도 함께 삭제CascadeType.MERGE : 준영속(datached) 상태의 부모 엔티티를 병합할 때, 그 변경사항을 자식 엔티티에도 적용CascadeType.REFRESH : 데이터베이스로부터 부모 엔티티의 상태를 다시 읽어올 때(refresh), 자식 엔티티도 함께 다시 읽어옴. (DB에서 발생한 다른 변경사항을 엔티티에 다시 반영하고 싶을 때 사용)CascadeType.DETACH : 부모 엔티티를 준영속 상태(detached)로 만들 때, 자식 엔티티도 함께 준영속 상태로 만듦. (특정 엔티티와 그 하위 엔티티들을 영속성 컨텍스트의 관리에서 제외하고 싶을 때 사용)영속성 전이가 부모의 상태를 전파하면, 고아 제거 옵션은 부모와 자식의 관계가 끊어지는 것을 감지
@OneToMany(orphanRemoval =true) 혹은 @OneToMany(orphanRemoval = false) 형태로 사용 (기본값 : false)
SQL은 데이터베이스의 테이블과 컬럼을 기준으로 데이터를 조회
→ SQL: SELECT * FROM members WHERE team_id = 1
JPQL은 우리가 만든 자바 엔티티 객체(Member, Team)와 그 필드(username, name)를 기준으로 쿼리를 작성
→ JPQL: SELECT m.username FROM Member m WHERE m.team = ?
1. 기본 조회
*// 전체 조회*
@Query("SELECT m FROM Member m")
List<Member> findAllMembers();
*// 조건 조회*
@Query("SELECT m FROM Member m WHERE m.age > :age")
List<Member> findByAgeGreaterThan(@Param("age") int age);
*// 단일 결과 조회*
@Query("SELECT m FROM Member m WHERE m.username = :username")
Optional<Member> findByUsername(@Param("username") String username);
2. 파라미터 바인딩
@Query("SELECT m FROM Member m WHERE m.username = :username AND m.age = :age")
List<Member> findMembers(@Param("username") String username,
@Param("age") int age);
3. Inner Join
@Query("SELECT m FROM Member m JOIN m.team t WHERE t.name = :teamName")
List<Member> findMembersInTeam(@Param("teamName") String teamName);
4. Left Join
@Query("SELECT m FROM Member m LEFT JOIN m.team t")
List<Member> findAllMembersWithTeam();
프로젝션(Projection)은 엔티티의 전체 필드가 아닌, 원하는 필드만 골라서 객체로 받아오는 기술
@DataJpaTest : JPA Repository만 테스트할 때 쓰는 어노테이션
Controller, Service 없이 Repository 관련 부분만 실행 (그래서 테스트가 더 빠름)
Postman 없이 코드로 DB 동작 검증 가능
MySQL 대신 H2라는 인메모리 DB를 사용
testImplementation 'com.h2database:h2'
testImplementation : 해당 의존성을 테스트 시에만 사용하겠다는 뜻
테스트 코드를 작성하는 방법론
Given : 테스트 준비
When : 테스트 실행
Then : 테스트 결과 검증
@Test
@DisplayName("멤버 저장에 성공한다.")
void saveAndFindById() {
// given
Member member = new Member("홍길동");
// when
Member savedMember = memberRepository.save(member);
// then
assertThat(savedMember.getId()).isNotNull();
}