6-keem
Gallery
About
© Powered by 6-keem

Spring Data JPA 사용하기

Backend
2025년 06월 10일
5분

Spring Framework

Series bookmark
  1. Spring 개요
  2. Spring 의존성 주입
  3. Spring MVC 패턴
  4. Spring MVC Web Form
  5. Spring JPA (Java Persistence API)
  6. Spring Entity Mapping
  7. Logging with SLF4J and Logback
  8. RESTful Web Service
  9. Restful Web Service with Spring
  10. Spring Boot 개요
  11. 첫 번째 Spring Boot 애플리케이션
  12. Spring Data JPA 사용하기
  13. Spring Security in Spring Boot 3
On this page
  • 1. 전통적 DAO 생성
  • 문제점
  • 2. Spring Data JPA 소개
  • 주요 레포지토리 인터페이스 계층
  • 3. CrudRepository
  • 4. PagingAndSortingRepository
  • 5. JpaRepository
  • 6. Spring Data JPA 사용 예시
  • 서비스 레이어 전통 방식
  • Spring Data JPA 적용
  • 7. 쿼리 메소드(Query Methods)
  • 8. @Query 어노테이션

이전 포스트
첫 번째 Spring Boot 애플리케이션
다음 포스트
Spring Security in Spring Boot 3
thumbnail.png
교과목 내용을 정리하기 위한 글입니다. 틀린 내용이 있을 수 있으니 참고하세요

1. 전통적 DAO 생성

JPA EntityManager를 직접 사용해 DAO를 작성하는 예시입니다.

@Repository
@Transactional
public class OfferDao {
 
    @PersistenceContext
    private EntityManager entityManager;
 
    public Product createProduct(Product product) {
        entityManager.persist(product);
        return product;
    }
 
    public Product findProduct(Long id) {
        return entityManager.find(Product.class, id);
    }
 
    public Product updateProduct(Product product) {
        return entityManager.merge(product);
    }
 
    public void deleteProduct(Long id) {
        Product product = findProduct(id);
        if (product != null) {
            entityManager.remove(product);
        }
    }
}

문제점

  • 엔티티마다 DAO 클래스를 반복 작성해야 함 (Product, Customer, Student 등)
  • Entity 타입과 기본 키 타입만 다를 뿐 코드가 유사함

2. Spring Data JPA 소개

Spring Data JPA를 사용하면 레포지토리 인터페이스만 정의해도 기본 CRUD 구현을 자동으로 제공합니다.

public interface ProductRepository
        extends CrudRepository<Product, Integer> {
}

위와 같이 선언하면 다음 메서드들이 자동 생성됩니다:

  • findAll()
  • findById(ID id)
  • save(S entity)
  • deleteById(ID id)

주요 레포지토리 인터페이스 계층

  • CrudRepository<T, ID>: CRUD 기본 기능 제공
  • PagingAndSortingRepository<T, ID>: 페이징·정렬 기능 추가
  • JpaRepository<T, ID>: 배치 삭제, 플러시 기능 등 JPA 확장 기능 제공

3. CrudRepository

CrudRepository가 제공하는 메서드 예시:

메서드설명
long count()엔티티 개수 조회
void delete(T entity)특정 엔티티 삭제
void deleteById(ID id)ID로 엔티티 삭제
Iterable<T> findAll()모든 엔티티 조회
Optional<T> findById(ID id)ID로 엔티티 조회
<S extends T> S save(S entity)엔티티 저장/수정
<S extends T> Iterable<S> saveAll(...)여러 엔티티 저장/수정

4. PagingAndSortingRepository

페이징과 정렬을 지원합니다.

public interface ProductRepository
    extends PagingAndSortingRepository<Product, Long> {
}

사용 예시:

@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;
 
    public List<Product> findAllSortedByPrice() {
        Sort sort = Sort.by(Sort.Direction.DESC, "price");
        return (List<Product>) productRepository.findAll(sort);
    }
 
    public Page<Product> findByPage(int page, int size) {
        Pageable pageable = PageRequest.of(page, size,
            Sort.by(Sort.Direction.ASC, "name"));
        return productRepository.findAll(pageable);
    }
}
  • 페이지 번호는 0부터 시작
  • Page<T>를 통해 페이징 정보(총 페이지, 총 요소 등) 제공

5. JpaRepository

JpaRepository는 PagingAndSortingRepository를 상속하며, 추가로 다음 기능을 제공합니다:

  • void flush()
  • void deleteAllInBatch() 등 배치 삭제
  • List<T> findAll()의 리턴 타입이 List<T>
public interface ProductRepository
    extends JpaRepository<Product, Integer> {
}

6. Spring Data JPA 사용 예시

서비스 레이어 전통 방식

@Service
public class ProductService {
    @PersistenceContext
    private EntityManager entityManager;
 
    @Transactional
    public Product save(Product product) {
        if (product.getId() == null) {
            entityManager.persist(product);
            return product;
        } else {
            return entityManager.merge(product);
        }
    }
 
    public Product findById(Integer id) {
        return entityManager.find(Product.class, id);
    }
 
    @Transactional
    public void deleteById(Integer id) {
        Product product = findById(id);
        if (product != null) {
            entityManager.remove(product);
        }
    }
 
    public boolean existsById(Integer id) {
        return findById(id) != null;
    }
}

Spring Data JPA 적용

public interface ProductRepository
        extends JpaRepository<Product, Integer> {
}
 
@Service
@Transactional
public class ProductService {
    @Autowired
    private ProductRepository repo;
 
    public Product get(long id) {
        return repo.findById(id).orElse(null);
    }
 
    public List<Product> listAll() {
        return repo.findAll();
    }
 
    public void save(Product product) {
        repo.save(product);
    }
 
    public void delete(long id) {
        repo.deleteById(id);
    }
}

7. 쿼리 메소드(Query Methods)

메소드 이름만으로 동적 쿼리 생성이 가능합니다.

public interface MemberRepository
    extends JpaRepository<Member, Long> {
    List<Member> findByUsername(String username);
    List<Member> findByUsernameAndAgeGreaterThan(
        String username, int age);
}
  • findByXxxAndYyy, findByAgeLessThan, findByFirstnameContaining 등 다양한 키워드 지원
  • 반환 타입: List<T>, Page<T>, Optional<T> 등

8. @Query 어노테이션

메소드 이름으로 표현하기 어려운 복잡한 쿼리는 @Query로 JPQL 또는 네이티브 SQL을 직접 지정할 수 있습니다.

public interface BoardRepository
    extends JpaRepository<Board, Long> {
 
    @Query("SELECT b FROM Board b WHERE b.title LIKE %:kw% " +
           "ORDER BY b.seq DESC")
    List<Board> searchByTitle(@Param("kw") String keyword);
 
    @Query(value = "SELECT seq, title FROM board " +
                   "WHERE title LIKE %?1% ORDER BY seq DESC",
           nativeQuery = true)
    List<Object[]> searchNative(String keyword);
}
  • JPQL: 엔티티명, 필드명 사용 (대소문자 구분)
  • 위치 기반(?1), 이름 기반(:param) 파라미터 바인딩 지원