취미로 음악을 하는 개발자

[Spring Framework] Spring Data JPA Repository 본문

공대인/Spring[Boot]

[Spring Framework] Spring Data JPA Repository

영월특별시 2019. 9. 29. 19:10
728x90

JPA를 이용하는 경우에는 별도의 클래스 파일을 작성하지 않고 원하는 인터페이스를 구현하는 것만으로도 JPA와 관련된 모든 처리가 끝나게 된다. 일반적으로 DAO라는 개념을 이용하듯이 JPA를 이용하는 경우에는 Repository라는 용어로 칭한다.


데이터베이스와 관련된 처리를 전통적인 JPA 처리 방식대로 EntityManager를 구성하고 트랜잭션을 시작하고 종료하는 코드를 만들 수도 있지만, JPA에는 기능이 복잡한 상황이 아닌 이상 간단하게 처리할 수 있는 Repository를 구성하는 것만으로도 충분한 기능들을 제공하고 있다.


JPA는 다음과 같은 인터페이스 구조를 사용하고 있다.



모든 인터페이스가 <T, ID> 두 개의 제네릭 타입을 사용하는 것을 볼 수 있는데, T는 엔티티의 타입 클래스를, ID는 식별자(PK)의 타입을 의미한다. 이 때, ID에 해당하는 타입은 반드시 java.io.Serializable 인터페이스 타입이어야만 한다.


실제 주로 사용하는 것은 CRUD(Create, Read, Update, Delete) 작업을 위주로 하는 CrudRepository 인터페이스나

페이징 처리, 검색 처리 등을 할 수 있는 PagingAndSortingRepository 인터페이스다.



프로젝트 생성




1
2
3
4
5
6
7
8
package org.zerock.persistence;
 
import org.springframework.data.repository.CrudRepository;
import org.zerock.domain.Board;
 
public interface BoardRepository extends CrudRepository<Board, Long>{
 
}
cs


인터페이스를 설계하는 것만으로도 많은 기능의 개발이 완료되기 때문에 개발의 생산성을 향상시킬 수 있다.


JPA를 이용하면 코드만으로는 아무것도 동작하지 않지만, 이와 같은 인터페이스를 기준으로 동적으로 실행할 수 있는 클래스를 동적으로 생성한다. 부모 인터페이스인 CrudRepository에는 다음과 같은 메소드들을 제공한다.


* Spring Data Core 2.2.0 기준

메소드

설명

 long count() 

 모든 엔티티의 개수

 void delete(T entity)

 주어진 엔티티 삭제 

 void deleteById(ID id) 

 식별키를 통한 삭제 

 void deleteAll(Iterable<? extends T> entities)

 주어진 모든 엔티티 삭제

 void deleteAll() 

 모든 엔티티 삭제 

 boolean existsById(ID id) 

 식별키를 가진 엔티티가 존재하는지 확인 

 Iterable<T> findAll() 

 모든 엔티티 목록 

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

 해당 식별키를 가진 엔티티 목록 반환 

 Optional<T> findById(ID id) 

 해당 식별키에 해당하는 단일 엔티티 반환 

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

 해당 엔티티들의 등록과 수정

 <S extends T>S save(S entity) 

 해당 엔티티의 등록과 수정 


개발 시에는 이러한 상속받은 기능에 필요한 메소드를 Repository 인터페이스에 추가하는 형태로 개발하게 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package org.zerock;
 
import java.util.stream.Stream;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.zerock.domain.Board;
import org.zerock.persistence.BoardRepository;
 
@RunWith(SpringRunner.class)
@SpringBootTest
public class BoardRepositoryTests {
    
    @Autowired
    private BoardRepository boardRepo;
    
    @Test
    public void inspect() {
        // 실제 객체의 클래스 이름
        Class<?> clz = boardRepo.getClass();
        System.out.println(clz.getName());
        
        // 클래스가 구현하고 있는 인터페이스 목록
        Class<?>[] interfaces = clz.getInterfaces();
        Stream.of(interfaces).forEach(inter -> System.out.println(inter.getName()));
        
        // 클래스의 부모 클래스
        Class<?> superClasses = clz.getSuperclass();
        System.out.println(superClasses.getName());
    }
    
    @Test
    public void testInsert() {
        Board board = new Board();
        board.setTitle("게시물 제목");
        board.setContent("게시물 내용 넣기");
        board.setWriter("user00");
        
        boardRepo.save(board);
    }
}
cs


위 클래스는 테스트용 클래스이므로 @SpringBootTest 어노테이션을 설정해준다.

위의 코드와 같이 BoardRepository 인터페이스를 구현한 객체를 주입하고 inspect()를 이용해서 테스트해보면 아래와 같은 출력이 나오는 부분이 있다.



클래스 이름이 com.sum.proxy-- 로 시작하는 것을 볼 수 있는데 이는 Java 언어의 동적 프록시 (Dynamic Proxy) 기능에 의해 동적으로 생성된 클래스를 의미한다고 보면 된다. 클래스 이름 중간에 $는 주로 내부 클래스임을 알려준다.

org.zerock.persistence.BoardRepository 부분이 나온것은 BoardRepository 인터페이스를 구현한 객체라는 사실을 알 수 있다.



Comments