[#1. SpringBoot 개념 이해하기!] SpringDataJPA의 유래, 사용법

BlackBean99·2022년 1월 15일
0

SpringBoot

목록 보기
6/20
post-custom-banner

Spring Data JPA 를 설명하기 전에 JPA를 먼저 이해해보자!

Spring Data JPA 가 나오기 전에는 순수 JPA를 이용하여 프로젝트를 진행했다.

  • CRUD같은 기본 기능을 실제로는 직접 구현했었다.

자 봐라! DataJPA를 사용하지 않고

public static void main(String[] args) {
  EntityManagerFactory factory = Persistence.createEntityManagerFactory("Factory");

  // db connection
  EntityManager manager = factory.createEntityManager();

  EntityTransaction transaction = manager.getTransaction();
  // 트랜잭션 시작
  transaction.begin();

  try {
    Member member = new Member();

    member.setUsername("Steven Gerrard");
    manager.persist(member); // db 저장

    Member findMember = manager.find(Member.class, member.getId()); // select 쿼리

    System.out.println(findTeam.getName());

    transaction.commit();
  } catch (Exception e) {
      transaction.rollback();
  } finally {
      manager.close();
      factory.close();
  }
}

실제로는 다음처럼 Repositorty를 선언하고 특정 기능들은 Repository에서 구현했다.

Repository

먼저 CRUD를 구현하기 위해 데이터 접근 계층인 Repository를 먼저 만든다.

특정 유저를 찾는 기능을 구현해보자
쿼리문을 이용해서 DB에 접근하여 해당 정보만 추출하는 방식을 이용한다.



@Repository
public class MemberRepository {
  @PersistenceContext;
  EntityManager em;

  public void save(Member member) {
    em.persist(member);
  }

  public void findByName(String name) {
    return em.createQuery("SELECT m FROM Member m WHERE m.name = :name", Member.class)
            .setParameter("name", name)
            .getResult();
  }
}

나같이 게으른 사람들을 위해 매번 같은 함수를 생성하기 귀찮아서 해당 기능을 제공하기 위해 Spring Data JPA가 탄생했따아아아!

Spring Data JPA 인터페이스

DataJPA가 뭘 해주는데?

  • findByUsername, save, update 등과 같이 간단하지만 단순 반복 작업들을\ Spring Data JPA 구현체인 Hibernate가 애플리케이션 실행 시점에 동적으로 자주 사용되는 쿼리 집합을 만들어
    우리의 UserRepository 인터페이스를 구현해준다.

그래서 기존 기능은 쿼리문을 날려서 값을 받아왔지만 JPQL ( 일단 JPA 에서 사용한 Query라고 생각하자 - 차후에 이 내용은 따로포스팅 하도록 하겠다.)

  • 우리가 자주 사용하는 CRUD를 굳이 JPQL로 작성하지 않더라도 인터페이스 하나만 상속받으면 사용할 수 있게 된다.

JPA 인터페이스의 기능

사용은 JpaRepository 인터페이스를 상속 받으면 된다.

그래서 아래와 같은 기능을 제공한다.

  • findAll() : 해당 엔티티 테이블에 있는 모든 데이터를 조회한다.
  • save() : 대상 엔티티를 DB에 저장한다.
  • saveAll() : Iterable 가능한 객체를 저장한다.
  • delete() : 데이터베이스에서 대상 엔티티를 삭제한다.

이외에도 더 많은 기능들이 존재하는데, JpaRepository 는 아래와 같이 다양한 기능이 정의된 인터페이스를 상속 받게 되는데, 이 인터페이스들 덕분에 우리는 단순 CRUD 외에 다양한 기능(Paging, Sorting)을 수행할 수 있다.

이걸 사용하기 위해 인터페이스의 계층 구조를 알아보자.

JPARepository 를 상속받아 사용하는 법

위에서 언급한 상속을 실제 코드와 함께 보자

public interface UserRepository extends JpaRepository<User, Long>{
}

위와 같이 제네릭 타입으로 지정한다.

  1. 엔티티
  2. 엔티티에서 사용하는 PK 데이터 타입
    - 데이터 엔티티와 PK, 연관관계는 차후에 포스팅 하도록 하겠다.
    User Entity에 접근하기 위해 User 테이블과 User 엔티티의 PK 데이터 타입인 Long을 제네릭에 삽입한다.

코드 실사용법

데이터 생성, 조회 기능을 구현해보자.

  • User.class
    엔티티 클래스

  • UserRepository.interface
    데이터 접근 계층인 Repository 인터페이스
    SpringDataJpa 의 힘을 빌리기 위해 JpaRepository를 상속 받는다.

  • UserRepositoryTest.class
    조회 쿼리를 테스트할 테스트 클래스

이 3개를 구현해보자

1. User


@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
}

@GeneratedValue(strategy = GenerationType.IDENTITY) 는 해당 id가 자동으로 생성해주는 어노테이션이라고 이해하면 된다.

위에서 계속 말한 JpaRepository 를 상속 받자.

2. UserRepository

public interface UserRepository 
extends JpaRepository<User, Long{}

3. UserRepositoryTest

@SpringBootTest
@Transactional
@Rollback(false)
class UserRepositoryTest {

    @Autowired
    UserRepository userRepository;

    @Test
    void querySingleRowTest() {
        // given
        List<User> generatedUsers = generateUsersForTest();
        userRepository.saveAll(generatedUsers);

        // when
        Optional<User> selectedUser = userRepository.findById(1L);

        // then
        assertEquals(selectedUser.get().getId(), 1L);
    }

    @Test
    void queriesMultipleRowTest() {

        // given
        List<User> generatedUsers = generateUsersForTest();
        userRepository.saveAll(generatedUsers);

        // when
        List<User> selectedAllUsers = userRepository.findAll();

        // then
        selectedAllUsers.forEach(selectedUser -> {
            System.out.println(selectedUser.toString());
        });

        // then 혹은
        assertAll(
                () -> assertEquals(selectedAllUsers.get(0).getId(), 1L),
                () -> assertEquals(selectedAllUsers.get(1).getId(), 2L),
                () -> assertEquals(selectedAllUsers.get(10).getId(), 11L)
        );
    }

    List<User> generateUsersForTest() {

        List<User> users = new ArrayList<>();

        for (long i = 1; i < 40; i++) {
            User user = User.builder().id(i).username("사용자 " + i).build();
            users.add(user);
        }
        return users;
    }
}

이와 같이 테스트할 수 있겠다.

아래 포스팅을 가져온 것입니다.
다음 포스팅은 JPA, ORM 내용을 다뤄보겠습니다.

Reference
https://wonit.tistory.com/469

profile
like_learning
post-custom-banner

0개의 댓글