[JPA] 1.JPA란?

JPA 시리즈 1편

1. JPA란?

 

처음 JPA를 접하게 되면, 종종 SQL을 자동으로 만들어주는 도구라고만 여기는 경우가 많습니다. 하지만 JPA를 단순히 SQL 자동 생성 기술로만 이해한다면 곧 한계에 봉착하게 됩니다. JPA의 진짜 본질은 객체의 상태 변화와 그 관계를 데이터베이스에 어떻게 반영할 것인가에 초점이 맞춰져 있습니다.

 

처음 JPA를 배우면 대부분 이렇게 떠올립니다. 엔티티를 만들고 persist()를 호출하면 insert가 나가고, 값을 바꿨더니 update 쿼리가 실행된다. 이 경험 때문에 JPA를 단순히 자바 객체를 데이터베이스에 저장해주는 기술이라고만 쉽게 정의하고 넘어가기 쉽습니다.

하지만 실제로 JPA의 구조와 개념은 이보다 훨씬 복잡하고 깊이가 있습니다. 예를 들어, 쿼리가 생각보다 많이 생성되는 이유, 직접 update를 호출하지 않았는데도 update가 실행되는 이유, 연관관계 설정 시 왜 한쪽만 바뀌면 안 되는지 등, 단순히 객체 저장만으로는 설명할 수 없는 여러 상황이 발생합니다.

그래서 JPA를 제대로 이해하려면 이 기술이 애초에 어떤 문제를 해결하려고 등장했는지부터 살펴보는 것이 중요합니다.

 

JPA는 제품명이 아니라 표준입니다

JPA란 Java Persistence API의 약자입니다. 말 그대로, 자바 환경에서 영속성을 다루기 위해 정해놓은 표준 명세라고 할 수 있습니다. 여기서 핵심은, JPA가 특정 제품명이 아니라는 점입니다. 우리가 흔히 사용하는 Hibernate는 JPA 표준을 구현한 대표적인 구현체이고, 그 외에도 여러 구현체가 존재합니다.

즉, 코드에서 EntityManager를 쓰고 @Entity를 붙이고 JPQL을 활용할 때는 JPA 표준 인터페이스를 사용하는 것이고, 실제로 SQL을 생성하거나 변경을 감지하는 일, 프록시 처리 등 구체적인 동작은 구현체가 담당합니다.

이 차이를 한 번 이해하게 되면, JPA가 단순한 라이브러리가 아니라 객체와 데이터베이스를 연결하는 일종의 공통 규약, 즉 약속에 가깝다는 점을 알 수 있습니다.

 

JPA가 필요한 이유

자바 객체와 관계형 데이터베이스는 태생적으로 구조가 완전히 다릅니다. 자바 객체는 서로를 참조하면서 동작하고, 상태와 행위가 한데 묶여 있습니다. 반면, RDB는 테이블과 컬럼, 그리고 외래 키와 조인이 중심입니다.

객체에서는 member.getTeam().getName()처럼 참조만 따라가면 팀 이름을 알 수 있지만, 테이블 구조에서는 member 데이터만 봐서는 팀 이름을 바로 알 수 없습니다. 반드시 team 테이블과 외래 키로 조인을 해줘야 하죠. 결국 객체의 세계는 그래프 탐색이 자연스럽고, 테이블의 세계는 집합 연산이 주가 됩니다.

문제는 대부분의 애플리케이션이 두 가지 모두를 동시에 사용할 수밖에 없다는 점입니다. 서비스 로직은 객체 중심으로 짜고 싶지만, 최종적으로 데이터는 관계형 데이터베이스에 저장됩니다. 그 결과, 객체를 테이블 구조에 맞게 펼쳐주고, 다시 조회 결과를 객체로 조립하는 반복적인 작업이 계속 이어질 수밖에 없습니다.

JPA는 객체와 데이터베이스 사이의 어색한 틈을 메우기 위해 등장한 기술입니다. 단순히 객체를 데이터베이스에 바로 저장하는 도구라기보다는, 서로 다른 두 세계가 만나는 경계에서 충돌이 일어나지 않도록 정리해 주는 하나의 계층이라고 볼 수 있습니다.

 

JPA가 하는 일은 단순 저장이 아니다

많은 분들이 JPA를 단순한 저장 기술로 생각하곤 하지만, 여기서 흔히 놓치는 부분이 바로 '영속성 컨텍스트'라는 개념입니다. JPA의 역할은 단순히 insert, update, delete와 같은 기본적인 명령에 머물지 않습니다. 어떤 객체가 현재 관리되고 있는지, 동일한 식별자를 가진 객체를 같은 객체로 볼 것인지, 객체의 값이 언제 바뀌었는지, 그리고 그 변화가 언제 데이터베이스에 반영되어야 하는지 등 여러 가지를 치밀하게 관리합니다.

예를 들어, 엔티티를 조회하고 나서 값을 바꿨다고 해서 곧바로 update 쿼리가 날아가는 것은 아닙니다. JPA는 해당 객체의 상태 변화를 조용히 추적하고, 가장 알맞은 시점에 데이터베이스와 동기화를 시도합니다. 덕분에 개발자는 객체를 자연스럽게 다루는 데 집중할 수 있고, 데이터베이스와의 동기화는 JPA가 책임지게 됩니다.

그래서 JPA를 단순히 쿼리를 대신 만들어주는 기술로만 보기보다는, 객체의 상태를 세밀하게 추적하며 이를 데이터베이스와 맞춰주는 역할에 더 가깝다고 이해하는 것이 옳습니다.

 

엔티티는 단순한 자바 클래스가 아니다

JPA에서 가장 기본적인 단위는 엔티티입니다. 보통 @Entity라는 애노테이션이 붙은 클래스를 떠올리지만, 그 이면에는 단지 애노테이션만이 아니라 '식별자를 가진 영속성 대상'이라는 더 중요한 의미가 담겨 있습니다.

@Entity
@Table(name = "members")
public class Member {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    protected Member() {
    }

    public Member(String name) {
        this.name = name;
    }

    public void changeName(String name) {
        this.name = name;
    }
}

엔티티는 단순히 데이터를 담는 그릇이 아닙니다. 이 객체는 영속성 컨텍스트에서 관리되고, 식별자를 기준으로 동일성을 보장받으며, 상태 변화가 꼼꼼히 추적됩니다. 잠시 데이터를 전달하는 용도의 DTO와는 근본부터 다른 성격을 가집니다.

엔티티를 제대로 이해하려면, 담고 있는 값 자체보다도 그 존재의 '정체성'에 더 주목해야 합니다. 이름이 바뀌거나 속성 값이 달라져도, 실제로는 같은 회원이면 여전히 동일한 회원입니다. JPA는 바로 이 동일성을 식별자를 통해 판별하고 관리합니다.

 

JPA의 핵심, '객체 상태 관리'

JPA를 설명하는 문장 하나를 꼽자면, 다음 문장이 가장 근접하다고 생각합니다.

JPA는 단순히 객체를 테이블로 변환하는 도구가 아니라, 객체의 상태 변경을 관계형 데이터베이스와 동기화하는 기술입니다.

이 하나의 문장을 기준으로 생각해 보면, JPA를 둘러싼 여러 개념들이 자연스럽게 연결됩니다. 왜 영속성 컨텍스트가 필요한지, 같은 엔티티를 동일한 객체로 취급하려고 하는 이유, 직접 update를 호출하지 않아도 변경 사항이 저장되는 원리, flush와 commit이 각각 어떤 역할을 하는지, 그리고 연관관계의 주인 개념이 왜 등장하는지도 모두 이 틀 안에서 이해할 수 있습니다.

결국 JPA는 객체 중심의 애플리케이션 구조와 관계형 데이터베이스 사이의 간극을 메우기 위해 고안된 여러 규칙과 원칙의 집합입니다. 객체와 테이블은 구조적으로 완전히 일치할 수 없기 때문에, 이 차이를 매번 사람이 다루지 않도록 JPA라는 프레임워크가 그 역할을 대신해줍니다.

 

JPA를 진짜로 이해한다는 것

JPA를 배운다고 해서 애노테이션 몇 개를 외운다고 끝나는 일은 아닙니다. @Entity, @Id, @OneToMany, @ManyToOne 같은 문법은 표면적인 부분일 뿐, 가장 중요한 것은 그 아래에서 돌아가는 원리와 동작 방식입니다.

예를 들어, 연관관계 매핑만 했다고 해서 객체 참조와 외래 키 문제가 완전히 해결되는 것도 아니고, 지연 로딩을 설정했다고 모든 쿼리가 자동으로 최적화되는 것도 아닙니다. 또, JPQL을 쓴다고 SQL 자체를 몰라도 되는 게 아닙니다. JPA가 많은 불편함을 줄여주긴 하지만, 데이터의 저장과 조회 과정을 완전히 감춰주는 마법 같은 기술은 아닙니다.

그래서 JPA는 편리함만을 기대하기 전에, 반드시 원리를 이해하고 접근해야 하는 기술입니다. 구조와 원리를 제대로 이해하고 쓰면 강력한 도구가 되지만, 무작정 사용하다 보면 내부에서 어떤 일이 일어나는지 알지 못한 채 헤매게 되는 순간을 자주 맞닥뜨릴 수 있습니다.

 

정리

오히려 객체와 테이블 사이의 근본적인 차이점을 파악하고, JPA가 이 간극을 어떤 원칙과 규칙으로 메우는지에 대한 깊은 이해가 필요합니다. 이런 시각으로 바라보면, JPA는 막연히 어렵게만 느껴지는 기술에서 점차 논리적이고 체계적인 도구로 다가오게 됩니다.

 

JPA 시리즈

  • 1. JPA란?
  • 2. 엔티티와 값 타입
  • 3. 영속성 컨텍스트
  • 4. 엔티티의 생명주기
  • 5. flush와 commit
  • 6. dirty checking
  • 7. 연관관계와 연관관계의 주인
  • 8. LAZY, EAGER, 프록시
  • 9. JPQL이 필요한 이유

 

다음 글
2편에서는 엔티티와 값 타입을 중심으로, JPA가 어떤 대상을 영속 관리 대상으로 보고 어떤 대상을 값으로 취급하는지 정리한다.

'Tech Stack > JPA' 카테고리의 다른 글

[JPA] 2. 엔티티와 값 타입  (0) 2026.03.16