[Spring] 스프링 JPA란 무엇인가? - 동작 원리와 처리 흐름 정리

스프링에서 DB 연동을 할 때 MyBatis와 함께 가장 많이 사용되는 기술이 바로 JPA(Java Persistence API)입니다. JPA는 SQL을 직접 작성하기보다, 엔티티(Entity)와 매핑 정보만 정의해두면 나머지 CRUD SQL을 자동으로 생성하고 실행해 주는 방식의 표준 ORM 기술입니다. 이번 글에서는 Spring과 JPA가 함께 동작하는 방식과 전체 처리 흐름을 정리해보려고 합니다.

 

JPA란 무엇인가?

JPA는 자바 진영에서 정의한 ORM(Object-Relational Mapping) 표준 스펙입니다. 실제 구현체로는 Hibernate, EclipseLink 등이 있고, 스프링 부트에서는 보통 Hibernate JPA를 기본 구현체로 사용합니다.

개발자는 엔티티 클래스 + 매핑 어노테이션만 정의하면 INSERT, UPDATE, DELETE, SELECT 쿼리를 직접 작성하지 않고도 JPA가 엔티티 상태 변화에 따라 SQL을 자동으로 만들어 DB에 반영해 줍니다.

  • ORM 기반 → 객체 중심으로 개발, SQL은 JPA가 생성
  • 엔티티와 테이블 매핑(@Entity, @Table, @Id, @Column 등)
  • 변경 감지(Dirty Checking)로 UPDATE 자동 처리
  • JPQL, Criteria, QueryDSL 등을 통한 쿼리 작성

 

  • Application: Service → Repository(인터페이스)
  • O/R Mapper: Spring Data JPA → JPA(Hibernate)
  • JDBC: JDBC Basic APIs, DataSource(커넥션 풀), JDBC Driver
  • DB: 실제 SQL 실행(Oracle, PostgreSQL 등)

 

요청 처리 순서

  1. ServiceRepository(JpaRepository) 메서드 호출
  2. Spring Data JPA가 구현체(프록시)로 EntityManager에 위임
  3. JPA/Hibernate가 JPQL/엔티티 상태를 SQL로 생성
  4. JDBC + DataSource + Driver가 DB에 전송 및 실행
  5. ResultSet → 엔티티로 매핑되어 Repository → Service로 반환
  6. 커밋 시점 Dirty Checking으로 변경 SQL 자동 실행

 

JPA 구성 요소

  • Entity : 테이블과 매핑되는 도메인 객체. @Entity 어노테이션 사용.
  • EntityManager : 엔티티를 저장/조회/삭제하는 JPA의 핵심 객체.
  • Persistence Context : 엔티티를 1차 캐시로 관리하는 논리적인 저장소.
  • Spring Data JPA Repository : JpaRepository를 상속받아 CRUD 기능 제공.
  • Transaction : @Transactional을 통해 트랜잭션 경계를 관리.

실제 개발자는 보통 Entity + Repository + Service를 작성하고, EntityManager 자체를 직접 다루는 일은 점점 적어지는 추세입니다.

 

예제 코드로 보는 JPA

 1. Entity 정의 

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

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String email;

    protected Member() { } // JPA 기본 생성자

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

    // getter/setter 생략
}

@Entity로 선언된 클래스는 JPA가 관리하는 엔티티가 되며, 필드는 컬럼과 매핑됩니다. (@Column을 사용해 세부 설정도 가능)

 

 2. Spring Data JPA Repository 

public interface MemberRepository extends JpaRepository<Member, Long> {

    // 메서드 이름 기반 쿼리 생성
    Optional<Member> findByEmail(String email);

}

JpaRepository<엔티티, ID타입>를 상속받으면 별도 구현 없이도 save, findById, findAll, delete 같은 기본 CRUD 메서드를 사용할 수 있습니다. 또한 위 예시처럼 메서드 이름 규칙만 맞추면 쿼리 메서드도 자동 생성됩니다.

 

 3. Service에서 사용하기 

@Service
@Transactional
public class MemberService {

    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    public Member create(String name, String email) {
        Member member = new Member(name, email);
        return memberRepository.save(member);
    }

    @Transactional(readOnly = true)
    public Member findMember(Long id) {
        return memberRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("회원이 존재하지 않습니다."));
    }

    @Transactional(readOnly = true)
    public List<Member> findMembers() {
        return memberRepository.findAll();
    }
}

@Transactional이 붙은 메서드 안에서 엔티티의 값을 변경하면, 트랜잭션 커밋 시점에 JPA가 변경 내용을 감지(Dirty Checking)해서 자동으로 UPDATE SQL을 생성·실행해줍니다.

 

JPA의 장점

  • SQL 자동 생성 : 기본 CRUD에 대해 SQL을 직접 작성할 필요가 거의 없음.
  • 객체 지향적인 모델링 : 엔티티 간 연관관계 매핑(1:N, N:1, N:M 등)이 가능.
  • 변경 감지 : 엔티티만 수정하면 UPDATE SQL은 JPA가 대신 처리.
  • 캐시 및 성능 최적화 : 1차 캐시, 지연 로딩(Lazy Loading) 등 제공.
  • Spring Data JPA와의 통합 : JpaRepository로 생산성이 크게 향상.

업무 도메인을 객체 중심으로 모델링하고 싶거나, 반복적인 CRUD 코드/SQL 작성량을 줄이고 싶을 때 JPA의 장점이 극대화됩니다.