02. Spring Data와 Spring Data JPA
- -
이번 시간에는 Spring Data project에 대해 살펴보자.
Spring Data
Spring Data란?
https://spring.io/projects/spring-data
Spring Data는 전통적인 데이터 저장소에 대한 사용 특성을 유지하면서 여러 형태의 데이터 저장소를 활용하기 위한 프로젝트이다.
프로그램에서 데이터를 영속적으로 저장하기 위해 과거에는 주로 관계형 데이터베이스를 많이 사용했고 데이터를 관리하기 위해 JDBC 기반의 기술들이 발전했지만 최근에는 비 관계형 데이터베이스, 맵 리듀스 프레임워크, 클라우드 기반 서비스들이 많이 등장했다. Spring Data는 다양한 데이터 저장소에 접근하는 다양한 기술들을 포함하는 포괄적인 프로젝트이다.
Spring Data를 사용하면 MySql 같은 관계형 데이터베이스를 사용하건 MongoDB 같은 NOSql 데이터베이스를 사용하건 동일한 방법으로 사용할 수 있게 한다. 이것이 Spring이 가져다주는 PSA(Portable Service Abstraction)의 묘미이다. PSA는 뒤에 다시 살펴보자.
주요 모듈
다음은 Spring Data의 주요 모듈이다.
모듈 | 설명 |
Spring Data Commons | 모든 Spring Data 모듈을 뒷밧침하는 핵심 컨셉으로 CrudRepository, PagingAndSortingRepository 인터페이스등을 제공한다. |
Spring Data JDBC | SimpleJdbcRepository 등 Spring-JDBC를 위한 Spring Data repository를 제공한다. |
Spring Data JPA | JPARepository, SimpleJpaRepository 등 JPA 활용을 위한 Spring Data Repository를 제공한다. |
Spring Data MongoDB | No-SQL인 MongoDB를 위해 MongoRepository 등 Spring Data Repository를 제공한다. |
Spring Data Redis | Key-Value 구조인 Redis를 위해 RedisRepository 등을 제공한다. |
Spring Data REST | 위 프로젝트들과 연동하여 데이터베이스에 저장된 데이터를 RESTful API로 노출시키는 작업을 자동화 한다. |
PSA(Portable Service Abstraction)
이전 쳅터에서 이야기 했듯이 스프링의 4대 특징이라면 스프링 삼각형에 잘 표현되어있듯이 DI, AOP, PSA 그리고 POJO이다.
이 중에서 PSA(Portable Service Abstraction: 이식 가능한 서비스 추상화)란 복잡한 기능을 추상화 즉 단순화 시켜서 여기 저기서 쉽게 적용할 수 있도록 만들기 위한 개념이다. 이 PSA의 사상도 스프링의 많은 부분에 녹아들어있다.
예를 들어 JPA를 학습하려면 공부해야 할 내용이 정말 많다. 초급자가 프로젝트에 JPA를 제대로 적용하려면 상당히 부담스러울 것이다. 하지만 Spring에서는 인터페이스를 통해 필요한 기능들을 추상화 해 두었기 때문에 크게 걱정할 필요는 없다.
Spring Data의 CrudRepository는 누가봐도 CRUD에 대한 기능들이 잘 정의되어있을 것 같다. 따라서 이 인터페이스에 있는 메서드들만 호출하면 CRUD는 바로 완료이다.
public interface UserRepository extends CrudRepository<User, String> {
User findByName(String name);
}
CrudRepository는 persistence 로직에 대한 추상화가 잘 되어있기 때문에 PSA 개념이 잘 적용 되어있는 예이다.
그런데 이 녀석은 어떤 방식으로 어디에 데이터를 저장하게 될까?
그것은 구현체가 추가되면 자동으로 결정된다. 만약 pom.xml의 의존성에 spring-boot-starter-data-jpa가 추가된다면 RDB에 JPA를 통해서 저장한다. spring-boot-starter-data-mongodb를 추가하면 Mongo DB를 활용하고 spring-boot-starter-data-redis를 추가하면 redis db를 활용하게 된다. Spring Boot의 자동 구성 기능에 의해 적절한 Bean이 알아서 추가되기 때문이다. 즉 모듈이 교체되더라도 비지니스 로직의 변화는 거의 발생하지 않게 된다. 방식이 바뀌었지만 변경할 내용이 없다니.. 너무나 좋을것 같다.
이처럼 Spring의 PSA는 개발 생산성을 높이고 코드 품질을 향상시키는데 도움을 준다. 이제 개발자는 데이터 접근 로직에 대해 복잡하고 귀찮은 문제에서 벗어나 비지니스 로직에 좀 더 집중할 수 있게 되고 효율적으로 애플리케이션 개발이 가능하게 될 것이다.
Spring Data의 하위 프로젝트들
Spring Data Commons
Spring Data Commons는 다른 여러 모듈에서 공통적으로 필요한 Repository interface에 대해 정의하는 모듈이다. Repository 는 데이터 접근 계층을 추상화한 마커 인터페이스이다. 즉 별도로 선언된 메서드는 없다.
package org.springframework.data.repository;
/**
* @param <T> the domain type the repository manages
* @param <ID> the type of the id of the entity the repository manages
*/
public interface Repository<T, ID> {}
Repository를 상속한 인터페이스로 CrudRepository와 PagingAndSortingRepository가 있다. 각 인터페이스에 선언된 메서드 이름만 살펴봐도 어떤 기능이 처리되는지 쉽게 알 수 있다.
package org.springframework.data.repository;
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity); // create & update
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
Optional<T> findById(ID id); // read
boolean existsById(ID id);
Iterable<T> findAll();
Iterable<T> findAllById(Iterable<ID> ids);
void deleteById(ID id); // delete
void delete(T entity);
void deleteAllById(Iterable<? extends ID> ids);
void deleteAll(Iterable<? extends T> entities);
void deleteAll();
long count();
}
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends Repository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
개발자는 이런 인터페이스를 통해 데이터 접근 로직을 쉽게 구현할 수 있고 반복적인 C/R/U/D 나 페이징 작업을 간소화할 수 있다.
Spring Data JPA
이미 JPA를 이용한 프로젝트를 경험한 경우는 Spring Data JPA를 접하면 고개를 갸우뚱하게 되는데 JPA에서 중요한 EntityManager를 어느 순간부터 사용하지 않기 때문이다. Spring Data JPA는 내부적으로 JPA를 사용하지만 JPA의 복잡한 부분은 숨기고 쉽게 사용할 수 있게 도와준다. (하지만 직접 사용하지 않는다는 말이지 EntityManager에 대한 이해는 아주 중요하다.)
다음은 Spring Data JPA에서 도메인 별 사용자 정의 repository를 만들때 기본적으로 상속하는 JpaRepository의 일부이다.
package org.springframework.data.jpa.repository;
@NoRepositoryBean
public interface JpaRepository<T, ID> extends
ListCrudRepository<T, ID>,
ListPagingAndSortingRepository<T, ID>,
QueryByExampleExecutor<T> {
void flush(); // 미반영된 변경 사항들을 DB에 즉시 반영 시킴
<S extends T> S saveAndFlush(S entity);
<S extends T> List<S> saveAllAndFlush(Iterable<S> entities);
void deleteAllInBatch(Iterable<T> entities);
void deleteAllByIdInBatch(Iterable<ID> ids);
void deleteAllInBatch();
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);
}
일반적으로 Spring Data JPA는 JPA 대비 다음과 같은 편의성을 제공해 준다.
- 반복적인 CRUD 작업의 자동화 및 페이징 및 정렬 처리의 단순화: JpaRepository는 앞서 살펴봤던 CrudRepository, PagingAndSortingRepository 등 인터페이스를 확장해서 간단히 데이터 접근 계층을 구성할 수 있다. 이들은 이미 C/R/U/D 뿐 아니라 페이징을 정의하고 있기 때문에 따로 구현할 것도 없어지고 동작을 의심할 필요 없으니 테스트도 간단해진다.
- 쿼리 메서드를 통한 쿼리 생성: Spring Data JPA는 메서드 이름만으로 쿼리를 자동으로 생성할 수 있게 해 준다. 예를 들어 findByEmail은 select * from table where email=? 에 해당하는 의미를 갖는다. 간단한 쿼리에는 정말 편하다.
List<User> findByNameAndAge(String name, int age);
--> select * from user where name=? and age=?;
long countByName(String name);
--> select count(*) from user where name=?
List<User> findByOrderByAgeAsc();
--> select * from user order by age asc;
- @Query 애너테이션: JPA에서도 native SQL을 직접 작성할 수 있었지만 EntityManager를 이용해야 하는 등 번거로움이 많다. @Query를 사용하면 JPQL은 물론 native SQL을 모두 작성할 수 있고 Repository와 함께 훨씬 편리한 쿼리의 작성이 가능하다.
@Query("SELECT COUNT(u) FROM User u WHERE u.name = ?1") // JPQL 사용 예
long countUsersWithName(String name);
@Query(value="SELECT * FROM users u WHERE u.email=?1",nativeQuery=true) // native SQL 사용 예
User findUserByEmail(String email);
- 도메인 클래스 컨버터: Spring Data JPA는 웹 요청에서 받은 ID를 통해 자동으로 도메인 객체를 검색해서 제공한다. 이 기능을 사용하면 개발자가 직접 조회 로직을 작성할 필요조차 없어진다.
@Controller
public class UserController {
@GetMapping("/user/{id}")
public String getUser(@PathVariable("id") User user, Model model) { // 이미 DB에서조회 됨
model.addAttribute("user", user);
return "userProfile";
}
}
'Spring Model > 01. Model' 카테고리의 다른 글
@Repository의 역할 (0) | 2024.03.22 |
---|---|
Connection Pool (0) | 2024.03.22 |
Entity vs VO vs DTO (0) | 2023.10.19 |
03. 프로젝트 구성 (0) | 2022.11.13 |
01. Model 영역과 Spring (0) | 2019.09.09 |
소중한 공감 감사합니다