[1] JPA 소개

ttt-1-2·2026년 3월 15일
post-thumbnail

교재: 자바 ORM 표준 JPA 프로그래밍 

JPA를 사용하면 SQL 자체보다 내가 만든 객체에 더 집중할 수 있다. 데이터베이스가 바뀌더라도(MySQL → Oracle 등) 애플리케이션 코드를 크게 바꾸지 않고 유지보수하기 쉬워진다.

예전에는 보통 다음과 같은 흐름으로 개발했다:

  • ORM 이전: Java → JDBC → SQL → DB 개발자가 직접 SQL을 작성하고, 조회 결과를 다시 자바 객체로 하나하나 매핑해야 했다.
  • ORM 이후: Java 객체 → ORM → SQL → DB 개발자는 객체 중심으로 개발하고, ORM이 중간에서 SQL 생성과 매핑을 도와준다.

즉, ORM은 객체와 관계형 데이터베이스 사이의 번역기 같은 역할을 한다. 자바는 객체를 사용하고 데이터베이스는 테이블을 사용하므로 둘 사이에는 구조 차이가 있다. ORM은 이 차이를 줄여 주어서 개발자가 조금 더 자연스럽게 객체지향적으로 개발할 수 있게 해준다.


1. SQL을 직접 다룰 때 발생하는 문제점

반복

ex: 회원 정보를 조회한다고 해보자.

  1. 조회용 SQL을 직접 작성한다.
  2. JDBC API를 사용해서 SQL을 실행한다.
  3. 결과(ResultSet)를 꺼내서 자바 객체에 하나씩 넣는다.

아래와 같이 Member 객체와 MemberDAO가 있다고 가정해보자.

public class Member {
    private String memberId;
    private String name;
}
public class MemberDAO {
    public Member find(String memberId) {
        // DB에서 회원을 조회하는 로직이 들어간다
        return null;
    }
}

겉으로 보면 find() 메서드 하나만 있으면 될 것 같지만 실제 내부에서는 꽤 많은 코드가 필요하다.

ex: DB 연결 얻기, SQL 문자열 작성, PreparedStatement 생성, 파라미터 바인딩, SQL 실행, ResultSet 조회, 컬럼 값을 꺼내서 Member 객체에 저장, 자원 반납(Connection, Statement, ResultSet 닫기)

→ 비즈니스 로직보다 JDBC 처리 코드가 더 많이 보이는 경우가 많다.

SQL에 의존적인 개발

SQL을 직접 다루면 자바 코드가 데이터베이스 구조에 강하게 묶이게 된다.

ex: 회원 연락처를 추가할 때 겉보기에는 필드 하나 추가한 것뿐이지만 실제로는 수정할 것이 많다.

// 회원 클래스에 연락처 필드 추가
pulic class Member {
	private String memberId;
	private String name;
	private String tel;
}

수정해야 하는 부분

  • 자바 객체에 필드 추가
  • DB 테이블에 컬럼 추가
  • INSERT SQL 수정
  • UPDATE SQL 수정
  • SELECT SQL 수정
  • ResultSet 매핑 코드 수정

계층 분할이 어려워진다

객체지향적으로 설계하면 보통 다음처럼 생각한다.

  • Member는 회원 객체다
  • Team은 팀 객체다
  • 회원은 한 팀에 속할 수 있다

자바 코드에서는 자연스럽게 이렇게 표현하고 싶어진다.

member.getTeam();

하지만 SQL 중심으로 개발하면 그렇게 단순하지 않다.

member.getTeam()을 호출한다고 자동으로 팀 정보가 나오는 것이 아니다. 개발자는 먼저 DAO 안을 열어 보고 어떤 SQL이 실행되고 있는지 확인해야 한다. (회원만 조회하는 SQL인지, 팀까지 조인해서 조회하는 SQL인지, 팀은 따로 다시 조회해야 하는지..)

→ 객체를 사용하는 입장에서는 그냥 member.getTeam() 하면 될 것 같지만, 실제로는 DAO 내부 SQL 구현을 알아야만 동작을 예측할 수 있다.

JPA와 문제 해결

JPA를 사용하면 개발자가 SQL을 직접 다루기보다 엔티티 객체를 중심으로 개발하게 된다.

// 저장 기능
jpa.persist(member);

// 조회 기능
String memberId = "helloId";
Member member = jpa.find(Member.class, memberId);

// 수정 기능
Member member = jpa.find(Member.class, memberId);
member.setName("이름변경")

// 연관된 객체 조회
Member member = jpa.find(Member.class, memberId);
Team team = member.getTeam();

필요한 시점에 JPA가 적절한 SELECT SQL을 실행해서 팀 정보를 가져온다 → 개발자는 “이 시점에 조인 SQL을 직접 날려야 하나?”를 덜 고민하게 된다.

2. 패러다임의 불일치

상속

  • 문제점: 객체는 상속 구조를 사용할 수 있지만 데이터베이스에는 상속 개념이 없다. JDBC를 사용하면 insert 시 여러 SQL을 작성해야 하고, 조회할 때는 여러 테이블을 JOIN 해야 한다.
  • JPA 해결: JPA는 객체 상속 구조를 그대로 저장할 수 있게 해 준다.

연관관계

  • 문제점: 객체는 참조로 관계를 표현하지만 데이터베이스는 외래 키로 관계를 표현한다.
  • JPA 해결: 객체 참조만 설정하면 JPA가 외래 키를 자동으로 관리한다.
member.setTeam(team);
em.persist(member);

객체 그래프 탐색

  • 문제점: JDBC에서는 객체처럼 자유롭게 탐색하기 어렵고 필요한 SQL을 직접 작성해야 한다.
  • JPA 해결: 객체처럼 자연스럽게 탐색할 수 있다.
Member member = em.find(Member.class, 1L);
Team team = member.getTeam();

비교

  • 문제점: DB는 PK 값으로 데이터를 비교하고 객체는 equals()로 객체를 비교한다.
  • JPA 해결: JPA는 같은 트랜잭션일 때 같은 객체가 조회되는 것을 보장한다.

3. JPA란 무엇일까?

  • ORM (Object-Relational Mapping): 객체와 관계형 데이터베이스를 매핑한다.
  • JPA(Java Persistence API)는 자바 진영의 ORM 기술 표준이다. (JPA는 실제 ORM 엔진이 아니라 ORM 기술의 규격이다. 실제 동작은 Hibernate, EclipseLink 같은 구현체가 수행한다.)

개발자는 JPA API를 사용하여 객체 중심으로 코드를 작성한다. 그러면 JPA 구현체가 내부적으로 SQL을 생성하여 데이터베이스와 통신한다.

개발자 코드
     |
     v
JPA API
(EntityManager, @Entity, @Id ...)
     |
     v
JPA 구현체 (Implementation)
------------------------------
| Hibernate                  |
| EclipseLink                |
| DataNucleus                |
------------------------------
     |
     v
SQL 생성
     |
     v
Database

JPA를 사용하면 생산성 향상, 유지보수 용이성, 객체와 관계형 데이터베이스 사이의 패러다임 불일치 해결 그리고 데이터 접근 추상화를 통한 벤더 독립성 등의 장점을 얻을 수 있다.

JPA를 사용하면 SQL 중심 개발에서 벗어나 객체 중심 개발이 가능해진다.

0개의 댓글