본문 바로가기
java

[개념] JPA란 무엇인가 : JPA와 엔티티의 연관관계

by zzingni 2025. 4. 8.

 

JPA(Java Persistence API)란 무엇인가?


 

스프링 데이터 JPA는 자카르타 퍼시스턴스 API(JPA)에 대한 저장소 지원을 제공한다. JPA 데이터 소스에 액세스해야 하는 일관된 프로그래밍 모델을 통해 애플리케이션 개발을 용이하게 한다.

 

자바 퍼시스턴스(Java Persistence, 이전 이름: 자바 퍼시스턴스 API/Java Persistence API) 또는 자바 지속성 API(Java Persistence API, JPA)는 자바 플랫폼 SE와 자바 플랫폼 EE를 사용하는 응용프로그램에서 관계형 데이터베이의 관리를 표현하는 자바 API이다.

 

기존에 EJB에서 제공되던 엔터티 빈(Entity Bean)을 대체하는 기술이다. 자바 퍼시스턴스 API는 JSR 220에서 정의된 EJB 3.0 스펙의 일부로 정의가 되어 있지만 EJB 컨테이너에 의존하지 않으며 EJB, 웹 모듈 및 JAVA SE 클라이언트에서 모두 사용이 가능하다. 또한, 사용자가 원하는 퍼시스턴스 프로바이더 구현체를 선택해서 사용할 수 있다.

 

JPA는 자바에서 ORM(Object-Relational Mapping)을 지원하는 표준 인터페이스이다.

 

JPA는 자바에서 객체를 데이터베이스에 저장하고 관리하기 위한 인터페이스와 기능을 제공하는 API.

자바 코드로 DB를 더 객체지향적으로 다룰 수 있게 도와주는 기술이며, 자바 객체와 데이터베이스 테이블을 매핑해주는 역할을 한다.

 

 

 

ORM(Object-relational mappng) 이란?


객체 관계 매핑(Object-relational mapping, ORM)은 데이터베이스와 객체 지향 프로그래밍 언어 간의 호환되지 않는 데이터를 변환하는 프로그래밍 기법이다. 객체 지향 언어에서 사용할 수 있는 "가상" 객체 데이터베이스를 구축하는 방법이다. 객체 관계 매핑을 가능하게 하는 상용 또는 무료 소프트웨어 패키지들이 있고, 경우에 따라서는 독자적으로 개발하기도 한다.

 

 

JPA와 Hibernate와의 관계


Hibernate는 JPA라는 명세의 구현체이다. 즉, 인터페이스를 직접 구현한 라이브러리이다. JPA와 Hibernate는 마치 자바의 interface와 해당 interface를 구현한 class와 같은 관계이다.

 

Hibernate는 Java로 작성된 프로그램에서 자연스럽고 유형이 안전한 형태로 관계형 데이터를 볼 수 있도록 한다.

 

 

위 사진은 JPA와 Hibernate의 상속 및 구현 관계를 나타낸 것이다.

 

JPA 의 핵심인 EntityManagerFactory, EntityManager, EntityTransaction을 Hibernate에서는 각각SessionFactory, Session, Transaction으로 상속받고 각각 Impl로 구현하고 있음을 확인할 수 있다.

“Hibernate는 JPA의 구현체이다”로부터 도출되는 중요한 결론 중 하나는 JPA를 사용하기 위해서 반드시 Hibernate를 사용할 필요가 없다는 것이다. Hibernate의 작동 방식이 마음에 들지 않는다면 언제든지 DataNucleus, EclipseLink 등 다른 JPA 구현체를 사용해도 되고, 심지어 본인이 직접 JPA를 구현해서 사용할 수도 있다. 다만 그렇게 하지 않는 이유는 단지 Hibernate가 굉장히 성숙한 라이브러리이기 때문일 뿐이다.

 

 

JPA의 장점


생산성 향상

 

  • SQL 작성이 줄어든다. (대부분의 CRUD를 자동 처리함)
  • 반복적인 코드(연결, 해제, 쿼리 작성 등) 감소

 

객체지향적인 설계 가능

 

  • 테이블이 아닌 객체 단위로 데이터를 다룰 수 있다.
  • 객체 간의 연관관계(예: 연관 매핑) 처리 가능

 

데이터베이스 독립성

 

  • SQL 의존도가 낮아서 DBMS 변경이 비교적 쉽다.
  • Dialect 설정만 바꾸면 다른 DB로 전환이 가능하다.

 

캐싱 기능

 

  • 1차 캐시, 2차 캐시 등으로 성능 최적화 가능

 

트랜잭션 처리 용이

 

  • 영속성 컨텍스트와 함께 트랜잭션 관리 자동화 

 

 

Entity란?


Entity는 JPA에서 데이터베이스 테이블과 매핑되는 자바 클래스를 말한다. 이 클래스 하나가 테이블 하나를 의미하고, 클래스의 필드들은 테이블의 컬럼과 연결된다. 예를 들어, member라는 테이블이 있다고 가정해보자.

 

@Entity
public class Member {

    @Id
    @GeneratedValue
    private Long id;

    private String username;
    private int age;

    // Getter, Setter 등 생략
}

 

  • @Entity 애너테이션: 이 클래스가 테이블로 매핑되는 Entity임을 JPA에게 알림
  • @Id: 해당 필드가 테이블의 기본 키(PK) 역할을 한다는 의미

Entity는 단순히 데이터를 담는 객체가 아니라, JPA가 직접 생명주기(persist, remove, merge 등) 를 관리하는 특별한 객체다. 그리고 대부분의 Entity는 단독으로 존재하지 않고, 다른 Entity들과 연관관계를 통해 연결된다.

 

 

객체와 테이블의 차이


JPA를 이해하려면 먼저 객체(Object)와 테이블(Table)의 근본적인 차이를 인식하는 게 중요하다. 객체지향 프로그래밍에서의 데이터 구조와, 관계형 데이터베이스에서의 구조는 전혀 다른 방식으로 데이터를 다룬다.

 

 

  객체는 '참조'로 연결된다.

 

자바에서 두 객체가 연관되어 있다고 할 때, 우리는 보통 필드로 참조를 사용한다. 예를 들어, Order 객체 안에 Member 객체가 있다면, Order는 Member를 참조하는 식이다.

 

public class Order {
    private Member member; // 객체 참조
}

 

이렇게 객체는 다른 객체를 참조(reference) 함으로써 연관관계를 표현한다. 이건 프로그래밍 언어가 메모리 상에서 객체를 어떻게 다루는지를 기반으로 하기 때문에 자연스럽고 직관적이다.

 

 

테이블은 ‘외래 키’로 연결된다

 

반면에 데이터베이스 테이블은 객체처럼 참조를 저장할 수 없다. 관계형 데이터베이스에서는 연관된 테이블끼리 외래 키(Foreign Key) 로 관계를 맺는다.

CREATE TABLE orders (
    id BIGINT,
    member_id BIGINT, -- 외래 키
    ...
);

 

orders 테이블의 member_id 컬럼은 members 테이블의 id 컬럼을 참조하는 외래 키다. 이 방식은 객체와 달리 값(value) 을 통해 연관 관계를 맺는다.

 

 

문제는 여기서 시작된다

 

이처럼 객체는 참조를 통해 관계를 만들고, 테이블은 외래 키로 관계를 맺기 때문에 JPA는 이 두 세계를 연결해주는 다리 역할을 해야 한다. 단순한 필드 매핑은 어렵지 않지만, 객체 간의 연관관계를 정확히 데이터베이스에 반영하려면 JPA가 내부적으로 꽤 많은 작업을 한다.

 

이걸 잘 이해하지 못하면,

  • 양방향 연관관계 설정 시 어느 쪽이 주인인지 헷갈리고
  • 연관된 데이터를 저장하거나 조회할 때 예상과 다른 결과가 나오며
  • 성능 이슈(N+1 문제 등)를 만나기도 한다.

그래서 "객체의 참조 vs 테이블의 외래 키" 개념을 먼저 확실히 이해하는 게 JPA 연관관계를 제대로 다루는 첫걸음이다.

 

JPA 연관관계 기본 개념


 

  단방향 vs 양방향

  • 단방향 연관관계 (가장 기본적인 형태)
@Entity
public class Order {
    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;
}

 

이렇게 하면 Order → Member 방향으로만 접근이 가능하다. 즉, 주문을 통해 회원 정보를 조회할 수 있지만, 회원이 자신이 한 주문 목록을 알 수는 없다.

 

  • 양방향 연관관계
@Entity
public class Member {
    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();
}

 

이제 Member 엔티티에서도 자신이 가진 Order 목록을 조회할 수 있다. 이때 중요한 건 mappedBy 속성이다.

 

 

  연관관계의 주인

 

JPA에서 양방향 연관관계를 맺을 때는 반드시 한쪽이 연관관계의 주인이 되어야 한다.
주인은 외래 키를 관리하는 쪽이고, 주인이 아닌 쪽은 단순히 매핑 정보만 갖고 있다.

 

예를 들어, 아래 예시에서 연관관계의 주인은 Order다.

@Entity
public class Order {
    @ManyToOne
    @JoinColumn(name = "member_id") // 외래 키 관리
    private Member member;
}

@Entity
public class Member {
    @OneToMany(mappedBy = "member") // 주인이 아님
    private List<Order> orders;
}
  • Order.member는 외래 키(member_id)를 실제로 가지고 있고
  • Member.orders는 그 외래 키를 참조할 뿐 직접 관리하지 않는다

이 주인 개념을 모르면 데이터가 저장되지 않거나, 양쪽 필드를 다 넣었는데도 DB에는 반영되지 않는 현상을 겪게 된다.

 

 

mappedBy의 의미

 

mappedBy = "member" 는 “이 연관관계는 Order 엔티티의 member 필드에 의해 관리된다”는 뜻이다. 다시 말해, Member.orders는 읽기 전용이다. 데이터베이스에 반영되는 연관관계 변경은 반드시 연관관계의 주인인 Order.member 를 통해 이루어져야 한다.

 

연관관계의 종류


JPA는 다양한 연관관계 매핑 애너테이션을 제공하는데, 실무에서 가장 많이 쓰이는 네 가지는 다음과 같다.

 

▶ @ManyToOne (다대일)

 

가장 일반적이고 많이 쓰이는 형태. 여러 개의 Order가 하나의 Member에 연결될 수 있다.

@Entity
public class Order {
    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;
}
  • Order가 외래 키를 가지고 있는 구조
  • 실무에서 거의 모든 연관관계가 이걸 중심으로 구성됨.

 

▶ @OneToMany (일대다)

 

하나의 Member가 여러 개의 Order를 가질 수 있다.

@Entity
public class Member {
    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();
}
  • mappedBy로 주인이 아님을 명시
  • 이 구조만으로는 외래 키 생성이 불가능 → 반드시 @ManyToOne과 같이 써야 함

 

 

▶ @OneToOne (일대일)

 

하나의 User가 하나의 Profile만 갖는 구조

@Entity
public class User {
    @OneToOne
    @JoinColumn(name = "profile_id")
    private Profile profile;
}
  • 실제로는 다대일처럼 동작함
  • 드물지만, 보안 정보나 상세 프로필 등 분리 저장할 때 사용

 

@ManyToMany (다대다)

 

예: 학생(Student)과 강의(Course)의 관계
한 명의 학생이 여러 강의를 수강하고, 하나의 강의에 여러 학생이 참여할 수 있음

 

@Entity
public class Student {
    @ManyToMany
    @JoinTable(
        name = "student_course",
        joinColumns = @JoinColumn(name = "student_id"),
        inverseJoinColumns = @JoinColumn(name = "course_id")
    )
    private List<Course> courses = new ArrayList<>();
}
  • 중간 테이블(student_course)이 자동으로 생성됨
  • 실무에서는 거의 사용하지 않고, 중간 Entity(예: 수강신청 엔티티)를 별도로 만들어 다대일-일대다로 분해하는 게 일반적

 

이 네 가지 애너테이션이 Entity 간 연관관계를 정의하는 핵심이다.
그 중에서도 @ManyToOne과 @OneToMany(mappedBy = ...) 조합이 가장 자주 사용되며, 연관관계의 주인은 외래 키를 가진 쪽이라는 점만 기억하면 대부분의 관계를 깔끔하게 구성할 수 있다.

 

Reference


 

 

Spring Data JPA :: Spring Data JPA

Oliver Gierke, Thomas Darimont, Christoph Strobl, Mark Paluch, Jay Bryant, Greg Turnquist Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that

docs.spring.io

 

 

자바 퍼시스턴스 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 자바 퍼시스턴스(Java Persistence, 이전 이름: 자바 퍼시스턴스 API/Java Persistence API) 또는 자바 지속성 API(Java Persistence API, JPA)는 자바 플랫폼 SE와 자바 플랫폼 EE를

ko.wikipedia.org

 

 

 

JPA, Hibernate, 그리고 Spring Data JPA의 차이점

개요 Spring 프레임워크는 어플리케이션을 개발할 때 필요한 수많은 강력하고 편리한 기능을 제공해준다. 하지만 많은 기술이 존재하는 만큼 Spring 프레임워크를 처음 사용하는 사람이 Spring 프레

suhwan.dev

 

 

Your relational data. Objectively. - Hibernate ORM

Idiomatic persistence for Java and relational databases.

hibernate.org

 

 

JPA 연관 관계 한방에 정리 (단방향/양방향, 연관 관계의 주인, 일대일, 다대일, 일대다, 다대다)

JPA에서 가장 중요한 것 JPA에서 가장 중요한 것을 뽑자면, "객체와 관계형 데이터베이스 테이블이 어떻게 매핑되는지를 이해하는 것"이라고 생각합니다. 🏅 왜냐하면 JPA의 목적인 "객체 지향 프

jeong-pro.tistory.com

 

'java' 카테고리의 다른 글

[개념] JAVA의 어노테이션과 라이브러리  (2) 2025.05.21
[개념] JPQL : 객체지향 쿼리 언어  (1) 2025.04.29