1. JPA란?
JPA(Java Persistence API)는 자바 객체와 관계형 데이터베이스 간의 매핑을 위한 자바 표준 ORM(Object Relational Mapping) 프레임워크입니다. SQL 대신 객체지향적인 방식으로 데이터를 관리할 수 있게 해주며, JPQL이라는 객체 중심 질의 언어를 사용합니다.
JPA는 아래의 대표적인 구현체로 사용됩니다:
- Hibernate (가장 널리 사용됨)
- EclipseLink
- OpenJPA 등
2. JPA의 주요 이점
- 객체지향적 데이터 모델링 가능 (Entity 기반 설계)
- 쿼리 작성 최소화 → 생산성 향상
- SQL 추상화로 DB 독립성 확보
- 1차 캐시를 통한 성능 향상 (영속성 컨텍스트)
3. 엔티티 클래스 정의
JPA에서 Entity는 DB의 테이블과 매핑되는 자바 클래스입니다.
@Entity
@Table(name = "members")
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
private int age;
// getter, setter 생략
}
- @Entity: 클래스가 JPA 엔티티임을 표시
- @Id: 기본 키(PK) 지정
- @GeneratedValue: 기본 키 생성 전략
- @Column: 칼럼 세부 설정
4. 영속성 컨텍스트 (Persistence Context)
JPA는 EntityManager를 통해 엔티티 객체를 관리합니다. 이 객체들은 영속성 컨텍스트라는 저장소에 의해 관리됩니다.
생명주기 단계
상태 설명
비영속 | 영속성 컨텍스트에 저장되기 전 상태 |
영속 | 영속성 컨텍스트에 저장된 상태 |
준영속 | 영속성 컨텍스트에서 분리된 상태 |
삭제 | DB에서 삭제 예정인 상태 |
예시
Member member = new Member("홍길동"); // 비영속
em.persist(member); // 영속
em.detach(member); // 준영속
em.remove(member); // 삭제
5. Repository - Spring Data JPA
스프링에서는 JPA를 쉽게 사용할 수 있도록 Spring Data JPA를 제공합니다. 인터페이스만 정의하면, 기본 CRUD 기능을 자동으로 생성해줍니다.
public interface MemberRepository extends JpaRepository<Member, Long> {
List<Member> findByName(String name);
}
- JpaRepository를 상속하면 CRUD, 페이징, 정렬 기능이 내장됩니다.
- 메서드 이름을 기반으로 자동으로 쿼리를 생성합니다.
사용자 정의 쿼리 예시
@Query("SELECT m FROM Member m WHERE m.age > :age")
List<Member> findOlderThan(@Param("age") int age);
6. 연관관계 매핑 (관계형 DB 모델링)
객체 간의 관계를 명시적으로 맺을 수 있습니다. (1:1, 1:N, N:M 등)
예시: 회원과 주문 (1:N)
@Entity
public class Member {
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
}
@Entity
public class Order {
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
}
- @OneToMany, @ManyToOne: 관계 방향 설정
- mappedBy: 주인이 아님을 명시 (읽기 전용)
- @JoinColumn: 외래 키(FK) 지정
7. Fetch 전략
- EAGER: 연관된 객체를 즉시 조회 (기본값: @ManyToOne)
- LAZY: 실제 사용할 때 조회 (지연 로딩)
@ManyToOne(fetch = FetchType.LAZY)
private Member member;
실제 운영에서는 LAZY가 권장되며, 필요시 JOIN FETCH를 사용해 함께 로딩합니다.
8. 영속성 전이 (Cascade)와 고아 객체 제거
Cascade
엔티티 간의 관계에 따라 연쇄적으로 영속/삭제 처리가 되도록 설정합니다.
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<Order> orders;
Orphan Removal
부모 엔티티에서 제거된 자식 엔티티를 자동으로 삭제합니다.
@OneToMany(mappedBy = "member", orphanRemoval = true)
private List<Order> orders;
9. Auditing (자동 시간 관리)
Spring Data JPA에서는 @CreatedDate, @LastModifiedDate 어노테이션을 통해 엔티티의 생성일자 및 수정일자를 자동으로 관리할 수 있습니다.
사용 예시
@EntityListeners(AuditingEntityListener.class)
public class BaseTimeEntity {
@CreatedDate
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime modifiedDate;
}
- @EnableJpaAuditing 설정 필요 (설정 클래스에서)
10. 복합 키 매핑 전략
1) @EmbeddedId 방식
@Embeddable
public class OrderId implements Serializable {
private Long memberId;
private Long productId;
}
@Entity
public class Order {
@EmbeddedId
private OrderId id;
}
2) @IdClass 방식
@Entity
@IdClass(OrderId.class)
public class Order {
@Id private Long memberId;
@Id private Long productId;
}
11. 상속 매핑
JPA는 객체지향 상속 구조를 테이블에 매핑할 수 있도록 지원합니다.
주요 전략
- SINGLE_TABLE: 하나의 테이블에 모든 자식 클래스 정보를 함께 저장
- JOINED: 부모 테이블과 자식 테이블을 조인해서 사용
- TABLE_PER_CLASS: 자식 클래스마다 별도의 테이블 생성
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "dtype")
public abstract class Item {
@Id @GeneratedValue
private Long id;
private String name;
}
@Entity
public class Book extends Item {
private String author;
}
12. QueryDSL 기본 설정과 사용
QueryDSL은 타입 세이프한 쿼리 작성을 지원하는 라이브러리입니다.
Gradle 설정
dependencies {
implementation 'com.querydsl:querydsl-jpa'
annotationProcessor 'com.querydsl:querydsl-apt'
}
기본 사용
JPAQueryFactory query = new JPAQueryFactory(em);
QMember m = QMember.member;
List<Member> result = query.selectFrom(m)
.where(m.age.gt(20))
.fetch();
13. BooleanBuilder를 활용한 동적 쿼리
사용자의 입력에 따라 조건을 유동적으로 조합할 수 있습니다.
BooleanBuilder builder = new BooleanBuilder();
if (name != null) {
builder.and(member.name.eq(name));
}
if (age != null) {
builder.and(member.age.gt(age));
}
List<Member> result = queryFactory.selectFrom(member)
.where(builder)
.fetch();
14. Specification (복잡한 조건 조합)
Spring Data JPA에서 제공하는 JpaSpecificationExecutor를 사용해 동적 조건 검색을 지원합니다.
public class MemberSpec {
public static Specification<Member> nameLike(String name) {
return (root, query, cb) -> cb.like(root.get("name"), "%" + name + "%");
}
}
15. JPA 테스트 전략
주요 어노테이션
- @DataJpaTest: JPA 테스트에 필요한 설정만 로드
- @Transactional: 테스트 후 자동 롤백
@DataJpaTest
public class MemberRepositoryTest {
@Autowired MemberRepository memberRepository;
@Test
public void testSave() {
Member m = new Member("홍길동", 30);
memberRepository.save(m);
}
}
16. 성능 최적화 전략
- 배치 처리 최적화: spring.jpa.properties.hibernate.jdbc.batch_size=100
- 지연 로딩 최적화: EntityGraph, Fetch Join 활용
- OSIV(Open Session In View): 성능 저하 원인 가능 → 비활성화 고려
spring.jpa.open-in-view=false
17. 실전 예제 모델링 (회원, 주문, 상품)
Member
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
}
Order
@Entity
public class Order {
@Id @GeneratedValue
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Member member;
}
Spring은 백엔드 개발에서 가장 핵심적인 프레임워크 중 하나로, 어렵더라도 반드시 학습해 두어야 할 기술입니다
스프링과 JPA를 공부할 때 반드시 참고해야 할 점은 예제 없이 개념만 공부하지 말고 반드시 작은 실습 프로젝트를 병행해야 합니다!
그리고 한 번에 모든 기능을 마스터하려고 하기보다, 하나의 기능을 다양한 케이스로 반복하면서 자연스럽게 체득하는 방식이 가장 효과적입니다.
실습이 답이다.
'KT에이블스쿨 7기' 카테고리의 다른 글
[KT AIVLE School 7기] CI/CD (1) | 2025.07.29 |
---|---|
[KT AIVLE School 7기] AI 마이크로서비스 모델링 (1) | 2025.07.28 |
[KT AIVLE School 7기] Spring Framework(3) (0) | 2025.06.24 |
[KT AIVLE School 7기] Spring Framework(2) (0) | 2025.06.24 |
[KT AIVLE School 7기] Spring Framework (0) | 2025.06.24 |