Spring Data JPA

shin·2024년 5월 19일

Spring Data JPA를 사용하면 JPA 기반(Java Persistence API) 리포지토리를 쉽게 구현할 수 있음

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  • 이미 라이브러리는 포함되어 있음
  • 기존 MemberRepository를 스프링 데이터 JPA로 변경

기존 MemberRepository 코드

package jpabook.jpashop.repository;

import jakarta.persistence.EntityManager;
import jpabook.jpashop.domain.Member;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@RequiredArgsConstructor
public class MemberRepository {

    private final EntityManager em;

    public void save(Member member){
        em.persist(member);
    }

    public Member findOne(Long id){
        return em.find(Member.class, id);
    }

    public List<Member> findAll(){
        return em.createQuery("select m from Member m", Member.class)
                .getResultList();
    }

    public List<Member> findByName(String name){
        return em.createQuery("select m from Member m where m.name = :name", Member.class)
                .setParameter("name", name)
                .getResultList();
    }

}

Spring Data JPA 적용

package jpabook.jpashop.repository;

import jpabook.jpashop.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
        
public interface MemberRepository extends JpaRepository<Member, Long> { 
    List<Member> findByName(String name);
}
  • MemberRepository를 interface로 생성한 다음 JpaRepository를 extends

    public interface MemberRepository extends JpaRepository<Member, Long> 
  • 스프링 데이터 JPA는 JpaRepository라는 인터페이스를 제공하는데, 여기에 기본적인 CRUD 기능이 모두 제공됨

    • 일반적으로 상상할 수 있는 모든 기능이 다 포함되어 있음
  • findByName처럼 일반화하기 어려운 기능도 메서드 이름으로 정확한 JPQL 쿼리를 실행함

    select m from Member m where m.name = :name`

Spring Data JPA가 제공하는 기능

package org.springframework.data.jpa.repository;
...
@NoRepositoryBean
public interface JpaRepository<T, ID> extends ListCrudRepository<T, ID>, ListPagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {

	void flush();

	<S extends T> S saveAndFlush(S entity);

	<S extends T> List<S> saveAllAndFlush(Iterable<S> entities);

	@Deprecated
	default void deleteInBatch(Iterable<T> entities) {
		deleteAllInBatch(entities);
	}

	void deleteAllInBatch(Iterable<T> entities);

	void deleteAllByIdInBatch(Iterable<ID> ids);

	void deleteAllInBatch();

	@Deprecated
	T getOne(ID id);

	@Deprecated
	T getById(ID id);

	T getReferenceById(ID id);

	@Override
	<S extends T> List<S> findAll(Example<S> example);

	@Override
	<S extends T> List<S> findAll(Example<S> example, Sort sort);
}
package org.springframework.data.repository;
...
@NoRepositoryBean
public interface ListCrudRepository<T, ID> extends CrudRepository<T, ID> {

	<S extends T> List<S> saveAll(Iterable<S> entities);

	List<T> findAll();

	List<T> findAllById(Iterable<ID> ids);

}
package org.springframework.data.repository;
...
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {

	<S extends T> S save(S entity);

	<S extends T> Iterable<S> saveAll(Iterable<S> entities);

	Optional<T> findById(ID id);

	boolean existsById(ID id);

	Iterable<T> findAll();
    
	Iterable<T> findAllById(Iterable<ID> ids);

	long count();

	void deleteById(ID id);

	void delete(T entity);
    
	void deleteAllById(Iterable<? extends ID> ids);

	void deleteAll(Iterable<? extends T> entities);

	void deleteAll();
}

정리

  • 개발자는 인터페이스만 만들면 됨
  • 구현체는 스프링 데이터 JPA가 애플리케이션 실행 시점에 주입해줌
  • 스프링 데이터 JPA는 스프링과 JPA를 활용해서 애플리케이션을 만들때 정말 편리한 기능을 많이 제공함
    • 단순히 편리함을 넘어서 때로는 놀라운 개발 생산성을 보여줌
  • 하지만 스프링 데이터 JPA는 JPA를 사용해서 이런 기능을 제공할 뿐이기 때문에 결국 JPA 자체를 잘 이해하는 것이 가장 중요함
profile
Backend development

0개의 댓글