JPA와 Spring data JPA 차이점 (+ Hibernate)

2023. 3. 27. 22:59Project/시네마그램

현재 면접 스터디를 진행 중에 있습니다.

개인 프로젝트 관련해서 받았던 질문들 중 대답을 잘하지 못했던 부분들은 따로 정리하고자 합니다.

 

 

 

 

질문

Skills 소개란에 JPA, Spring Data JPA 적혀있는데 둘의 차이점을 알고 있나요? 

 

 

 

 

😅 사실..

비슷해 보이는 용어의 차이점을 알고 있는지 확인하는 질문입니다.

개인 프로젝트를 진행하면서 JPA와 Spring data JPA를 사용했지만 그당시 명확한 차이점을 말할 수 없었습니다. 

 

왜일까..?

JPA 공부를 하다보면 EntityManager를 통해 entity관련 CRUD를 한다고 나와있습니다. 하지만 저의 경우 실제 애플리케이션 코드 구현시 EntityManager를 사용하지 않고 Repository 인터페이스를 사용했었는데요.

 

이유가 어떻든 사용하는 기술에 대한 명확한 개념이 정립되기 전에 바로 프로젝트를 하다 보니 생긴 문제였습니다. 

 

 

 

 

하나씩 정리

JPA는 객체-관계 매핑(ORM)을 위한 표준 명세인 인터페이스이다.

JPA는 Java Persistence API의 약자로, 자바 애플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스와 어노테이션의 표준 집합을 정의합니다. 

여기서 주목할 부분은 JPA는 특정 기능을 하는 라이브러리가 아닌 인터페이스라는 점입니다. 

 

자바 어플리케이션에서 관계형 데이터베이스를 어떻게 사용해야 하는지를 정의하는 한 방법일 뿐이고 단순한 명세이기에 구현은 없고, 다양한 ORM 프레임워크(예: Hibernate, EclipseLink, OpenJPA 등)에서 구현할 수 있는 공통 API를 제공합니다.

 

 

 

 

그럼 Hibernate는 어떤 것일까요? 

Hibernate는 JPA의 구현체이다

인터페이스를 직접 구현한 라이브러리입니다. JPA와 Hibernate 관계자바의 interface와 해당 interface를 구현한 class와 같은 관계입니다.

 

Hibernate는 JPA의 모든 기능을 지원하며 Hibernate는 객체와 관계형 데이터베이스 간의 매핑을 자동으로 처리해서 개발자가 일일이 SQL 쿼리를 작성하지 않도록 도와줍니다.

 

Hibernate는 JPA의 구현체입니다. 즉, JPA를 사용하기 위해서 반드시 Hibernate'만'을 사용할 필요가 없다는 것입니다. Hibernate가 마음에 들지 않으면 다른 JPA 구현체를 사용할 수 있습니다.

 

 

 

Spring Data JPA는 JPA 기반 애플리케이션 개발을 보다 간편하게 만드는 라이브러리/프레임워크이다. 

Spring으로 개발하면서 EntityManager를 직접 다뤄본 적이 왜 없을까 생각해 봤을 때,  DB에 접근할 필요가 있는 대부분의 상황에서는 Repository를 정의하여 사용했기 때문이었습니다. 

이 Repository가 바로 Spring Data JPA의 핵심입니다. 

 

Spring Data JPA는 Spring에서 제공하는 모듈 중 하나로, JPA 위에 추가적인 기능을 제공하여 JPA 기반 애플리케이션 개발을 보다 간편하게 만드는 라이브러리/프레임워크입니다.

 

 

이는 Repository라는 인터페이스를 제공함으로써 이루어집니다. 사용자가 Repository 인터페이스에 정해진 규칙대로 메서드를 입력하면, Spring이 알아서 해당 메서드 이름에 적합한 쿼리를 날리는 구현체를 만들어서 Bean으로 등록해 줍니다. 

 

CRUD 연산, 페이징, 정렬과 같은 JPA 리포지토리를 구현하는 데 필요한 반복적인 코드 양을 줄이는 인터페이스와 클래스를 제공합니다. Spring Data JPA는 또한 쿼리 메서드와 사용자 정의 쿼리를 지원하며, Spring 표현 언어(SpEL)와 유사한 구문을 사용하여 작성할 수 있습니다.

 

 

 

자주 사용하거나  내가 사용해 본  Spring Data JPA  예

1.  모든 엔티티 조회 .findAll()

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List<User> findAll() {
        return userRepository.findAll();
    }
}


2. 특정 id를 가진 엔티티 조회 .findById(Long id)

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public Optional<User> findById(Long id) {
        return userRepository.findById(id);
    }
}


3. 특정 이름으로 엔티티 조회 .findByName(String name)

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List<User> findByName(String name) {
        return userRepository.findByName(name);
    }
}


4. 엔티티 저장 .save()

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User save(User user) {
        return userRepository.save(user);
    }
}

 

5. 엔티티 업데이트 .save()

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User update(User user) {
        return userRepository.save(user);
    }
}

 

6. 엔티티 삭제 .delete()

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public void delete(User user) {
        userRepository.delete(user);
    }
}


7. 페이지네이션 기능을 이용해 엔티티 조회

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public Page<User> findAll(Pageable pageable) {
        return userRepository.findAll(pageable);
    }
}

 

8. 정렬 기능을 이용하여 엔티티를 조회하는 방법

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List<User> findAll(Sort sort) {
        return userRepository.findAll(sort);
    }
}

 

9.  Native Queries 네이티브 쿼리

public interface LikesRepository extends JpaRepository<Likes, Long> {

    @Modifying
    @Query(value = "INSERT INTO likes(image_id, user_id, created_date) VALUES(:imageId, :sessionId, now())", nativeQuery = true)
    int cLikes(@Param(value = "imageId") Long imageId, @Param(value = "sessionId") Long sessionId);
}

 

10. Named Queries 네임드 쿼리

@Entity
@NamedQuery(name = "Employee.findByLastName", query = "SELECT e FROM Employee e WHERE e.lastName = ?1")
public class Employee {
    // ...
}

 

11. Auditing 감사

엔티티를 생성하거나 업데이트할 때 자동으로 생성일과 수정일을 감사하는 방법을 보여줍니다.

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {

    @CreatedDate
    private LocalDateTime createdDate;

    @LastModifiedDate
    private LocalDateTime modifiedDate;

}

 

 

 

🙄 만약 Spring data JPA를 사용하지 않고 JPA만 사용한다면?

JPA를 사용할 때는 EntityManager를 사용하여 데이터베이스 기능을 사용해야 합니다.

EntityManager는 영속성콘텍스트를 관리하며, 이는 특정 영속성텍스트가 관리하는 엔티티 인스턴스의 집합입니다. 

 

반면에 Spring Data JPA를 사용할 때는 Repository 인터페이스를 사용하여 EntityManager 대신에 사용할 수 있습니다. CRUD (생성, 읽기, 갱신 및 삭제) 작업과 같은 일반적인 데이터베이스 작업을 작성하지 않아도 되는 코드를 제공합니다.

 

 

 

 

개인 프로젝트의 Spring Data JPA 관련 포스팅

Pageable을 사용해 Pagination 구현

Auditing - 시간 한 곳에서 관리

쿼리 메서드 기능

 

 

 

 

 

 

 

답변

"JPA는 Java에서 객체-관계 매핑을 위한 표준 명세로 인터페이스 입니다.

Spring Data JPAJPA 기반 애플리케이션 개발을 보다 쉽게 만들기 위해 JPA 위에 추가적인 기능과 추상화를 제공하는 라이브러리/프레임워크입니다."

 

 

 

 

 

 

 


 

 

참고:

Spring Data JPA 공식 문서

https://suhwan.dev/2019/02/24/jpa-vs-hibernate-vs-spring-data-jpa/