Spring Framework

교과목 내용을 정리하기 위한 글입니다. 틀린 내용이 있을 수 있으니 참고하세요
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
) 파라미터 바인딩 지원