CS 잡지식

Spring Data JPA에 대한 OverView

JIN_YOUNG _KIM 2023. 5. 7. 12:11

Spring Data JPA

-> Spring Framework와 JPA이란 기반 위에서, [JPA]를 정말 편리하게 사용할 수 있게 해주는 Spring에서 제공하는 라이브

러리이다.

우리가 여태껏 복잡하게 순수 JPA만으로 개발해 왔던 Repository 구현체를 개발하지 않고, Spring에서 제공하는 

[인터페이스]에서 [등록],[삭제],[수정] 등의 CRUD, 기본적으로 제공하므로 개발자는 그 API를 가져다 쓰기만 하면 된다. 

(Repository 관련 개발 코드가 확연히 줄어 든다)

그러나, Spring에서 제공하는 Spring Data JPA는 JPA의 너무 많은 부분들을 자동화 및 추상화를 하기 때문에, 

Spring Data JPA를 잘 사용하기 위해서는, Spring과 JPA에 대해서 100% 잘 알고 있어야만 활용 또한 잘 할 수가 있다.

 

여기서는 순수 JPA의 어떤 문제점 때문에 Spring Data JPA가 사용되는지 알아 보자!

 

@Repository
@RequiredArgsConstructor
public class MemberdJpaRepository {

    @Autowired
    private final EntityManager entityManager;

    public Member save(Member member){

        entityManager.persist(member);
        return member;
    }

    public void delete(Member member){
     
        entityManager.remove(member);
    }

    //전체 조회
    public List<Member> findAll(){

        return entityManager.createQuery("select m from Member m",Member.class)
                .getResultList();

    }


    //단건 조회
    public Member find(Long memberId){

        return entityManager.find(Member.class,memberId);

    }
    //위 find() 메서드와 기능이 똑같지만, 반환형을 Optional 클래스로 해 줬을 뿐!
    public Optional<Member> findById(Long id){

        Member member = entityManager.find(Member.class, id);
        return Optional.ofNullable(member); // member 객체를 Optional 객체로 한 번 Wrapping한다.
    }

    //조회된 객체의 개수
    public Long count(){

        return entityManager.createQuery("select count(m) from Member m",Long.class)
                .getSingleResult();

    }
    
}
@Repository
@RequiredArgsConstructor
public class TeamRepository {

    private final EntityManager entityManager;


    public Team save(Team team){

        entityManager.persist(team);
        return team;
    }

    public void delete(Team team){
        entityManager.remove(team);
    }

    public List<Team> findAll(){
        return entityManager.createQuery("select t FROM Team t",Team.class)
                .getResultList();
    }

    // 단일 조회
    public Team find(Long id){
        Team team = entityManager.find(Team.class, id);
        return team;
    }

    // 단일 조회 with Optional
    public Optional<Team> findById(Long id){

        Team team = entityManager.find(Team.class, id);
        return Optional.ofNullable(team);

    }

    public Long count(){

        return entityManager.createQuery("SELECT count(t) FROM Team t",Long.class)
                .getSingleResult();
    }

}

 

MemberRepository와 TeamRepository를 비교를 해 보자. 

구현한 메서드가 기본적으로 같거나 거의 비슷하다.

Repository 계층에서는 기본적으로 기본적인 CRUD가 거의 다 같고, 디테일한 부분만 사실 다르다. 

그럼에도 불구하고, MemberRepository,TeamRepository를 각각 중복 구현을 해야 한다는 번거로움이 있다. 

만약 Repository가 2개가 아니라 10개라면???(실제 프로젝트에서 Repository가 달랑 2개인 경우는 거의 없다)

-> 이러한 중복 코딩 문제를 Spring Data JPA가 해결해준다. 

(참고로, JpaRepository<>를 [공통 인터페이스]라고 부른다)

//@Repository : Spring Data JPA에서는 필요X
public interface MemberReposiotry extends JpaRepository<Member,Long> {

}

Spring(정확히는, Spring Data JPA)이 JpaRepository<>를 상속받은 [인터페이스]를 보고 [자동]으로 인터페이스에 대한

구현체(Proxy 구현체)를 생성해서 주입해 준다. 

 

 

class MemberReposiotryTest {

    @Autowired
    MemberReposiotry repository; // Spring Data JPA를 설정한 인터페이스!(구현체는 Spring Data JPA가 자동 생성해서 주입)
    
      @Test
    @Transactional(readOnly = false)
    @Rollback(value = false)
    public void basicCRUD(){

        Member member1 = new Member("member1");
        Member member2 = new Member("member2");
        repository.save(member1); // Spring Data JPA에서 제공하는 SAVE()이다.
        repository.save(member2);

        Optional<Member> findMember1 = repository.findById(member1.getId());  // Spring Data JPA에서 제공하는 findByID()이다.
        Optional<Member> findMember2 = repository.findById(member2.getId());
        //단일 조회 검증
        assertThat(findMember1.get()).isEqualTo(member1);
        assertThat(findMember2.get()).isEqualTo(member2);


        //리스트 조회 검증
        List<Member> all = repository.findAll();  // Spring Data JPA에서 제공하는 FindAll()이다.
        assertThat(all.size()).isEqualTo(2);

        //삭제 검증
        repository.delete(member1);  // Spring Data JPA에서 제공하는 DELETE이다.
        repository.delete(member2);

        long delete_count = repository.count();
        assertThat(delete_count).isEqualTo(0);
    }

Spring Data는 JPA뿐만 아니라, MONGO, REDIS 등 여러 DB에 공통적인 기능을 제공하는 계층이고

Spring Data [JPA]는 JPA에 특화된 기능을 제공하는 인터페이스이다.