Cascade는 부모가 어떤 행동(예: 저장, 삭제)을 할 때, 자식에게도 그걸 자동으로 같이 해주는 기능
부모 객체를 저장할 때 → 자식도 자동으로 저장
부모를 삭제할 때 → 자식도 같이 삭제
| 타입 | 설명 | 사용 예시 |
|---|---|---|
PERSIST | 부모를 저장하면 자식도 저장 | 새로운 회원과 할 일을 같이 저장할 때 |
REMOVE | 부모를 삭제하면 자식도 삭제 | 회원을 삭제하면 할 일도 삭제되게 할 때 |
MERGE | 부모의 변경사항을 자식에도 적용 | 수정 시 함께 반영되도록 할 때 |
REFRESH | DB에 있는 걸로 다시 초기화할 때 자식도 같이 초기화 | 캐시 무효화 등에서 |
DETACH | 영속성 컨텍스트에서 부모와 자식을 같이 분리할 때 | |
ALL | 위의 모든 걸 다 포함 | 전부 다 같이 할 때, 주의 필요! |
'고아 객체'는 말 그대로 더 이상 부모가 없는 자식 객체
만약 부모에서 자식을 제거했을 때, 자식이 혼자 남게 되면 어떻게 될까?
orphanRemoval = true
이러케 설정하면 → 그의 자식 객체도 자동으로 삭제!
하지만 ,,,,
❗ 자식이 여러 부모를 가질 수 있을 때는?
자식이 다른 부모에게도 연결되어 있는데, 한 부모에서 제거했다고 바로 삭제되면?
아직 필요한 자식인데 실수로 삭제될 수 있다 ㄷㄷㄷ EVA
📌
cascade = ALL과orphanRemoval = true를 함께 쓸 때는 이 설정이 끼칠 영향을 항상 생각하기
(특히 자식이 여러 부모와 연결될 가능성이 있는 경우)
QueryDSL은 SQL을 자바 코드처럼 작성하게 해주는 도구!
👉 마치 자바로 SQL을 짜는 너낌
→ 더 타입 안정성 있고, 자동완성도 되고, 실수도 줄어들 수 있땅
(기존 쿼리나 JPA는 스펠링 하나만 틀려도 안되는 경우가 정말 많았다ㅠㅠ)
✅ QueryDSL 장점
자바 코드처럼 쿼리 작성 가능 → 오타 줄어듦!
컴파일 타임에 오류 잡을 수 있음
IDE 자동완성이 지원
JPA보다 복잡한 조건 검색을 더 깔끔하게 쓸 수 있다
1. Gradle에 dependency 추가
dependencies {
implementation "com.querydsl:querydsl-jpa"
annotationProcessor "com.querydsl:querydsl-apt"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
}
def querydslDir = "$buildDir/generated/querydsl"
sourceSets {
main.java.srcDirs += querydslDir
}
tasks.withType(JavaCompile) {
options.annotationProcessorGeneratedSourcesDirectory = file(querydslDir)
}
이 설정을 하면, QueryDSL이 Q클래스라는 걸 자동으로 만들어준다
@Configuration
public class JpaConfiguration {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
@PersistenceContext
: JPA에서 DB랑 통신할 때 쓰는 EntityManager를 주입
JPAQueryFactory
: QueryDSL로 쿼리를 만들 수 있게 도와주는 도구!
→ 이걸 @Bean으로 등록하면, 다른 곳에서 @Autowired로 쉽게 쓸 수 있다
@Repository
@AllArgsConstructor
public class TodoCustomRepositoryImpl implements TodoCustomRepository {
private final JPAQueryFactory jpaQueryFactory;
@Override
public Optional<Todo> findByIdWithUser(Long todoId) {
QTodo qTodo = QTodo.todo;
QUser qUser = QUser.user;
Todo result = jpaQueryFactory.selectFrom(qTodo)
.leftJoin(qTodo.user, qUser).fetchJoin() // 연관된 유저도 한 번에 조회
.where(qTodo.id.eq(todoId)) // 조건: id가 todoId와 같은 것
.fetchOne(); // 하나의 결과만 조회
return Optional.ofNullable(result);
}
}
QTodo, QUser는 QueryDSL이 만들어준 클래스! → 자동완성!!!
fetchJoin()은 연관된 객체도 한 번에 가져온다 (→ N+1 문제 방지!)
fetchOne()은 결과를 1개만 가져올 때 사용
(여러 개 가져올 땐 fetch() 사용)