본문 바로가기

더 나은 엔지니어가 되기 위해/지금은 안쓰는 자바

[스프링 부트 개념과 활용] 데이터 2. JPA

인프런에서 백기선님의 스프링부트 개념과 활용 강의를 듣고, 개인적으로 공부하며 핵심만 정리한 글입니다.

JPA 사용법

1) Dependency 추가

pom.xmlspring-boot-starter-data-jpa 를 추가해주자.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

2) Entity Class 정의

Entity 는 RDBMS 에서 데이터 테이블을 객체화 시킨 것이다.
즉, 이 클래스는 테이블의 이름과 컬럼들에 대한 정보를 가진다.

이제 데이터베이스의 레코드로 쓰일 데이터 Entity 를 정의하자.
Entity 는 기본적으로 IdGetter, Setter 를 가지고 있어야 한다.

// Account.java

@Entity
public class Account {

  @Id @GeneratedValue
  private Long id;

  private String username;
  private String password;

  ...
  getter, setter, equals, hashCode
}

3) Repository 정의

해당 Entity 를 다루는 데이터 테이블에 접근하는 Repository 를 Interface 로 정의하자.
기본적으로 JpaRepository<'Entity Class', 'ID'> 를 상속받아 구현한다.

import org.springframework.data.jpa.repository.JpaRepository;

public interface AccountRepository extends JpaRepository<Account, Long> {
}

4) 데이터베이스 연결

이제 사용할 DB 를 설정하자. 여기서는 PostgreSQL 을 사용하고, 설정하는 법은 이전 포스팅에서와 같다.

<!-- pom.xml -->

<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <scope>test</scope>
</dependency>
# application.properties

spring.datasource.url=jdbc:postgresql://localhost:5432/springboot
spring.datasource.username=heumsi
spring.datasource.password=pass

이제 어플리케이션을 구동하면 문제 없이 잘 돌아가는 것을 확인할 수 있다.

JPA 테스팅

JPA 를 테스팅할 때, 실 서비스에 사용되는 DB 를 사용하면 안된다.
이유는 너무나 자명하게도, 테스트 내 일어나는 수행 결과가 서비스에 반영되면 안되기 때문.

따라서, 테스팅 환경용 DB 를 설정해줘야 하는데 보통은 인메모리 DB 인 h2 를 사용한다고 한다

1) 테스팅용 DB, h2

h2 를 사용하기 위해 다음과 같이 dependency 를 추가해주자.

<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <scope>test</scope>
</dependency>

scopetest 로 줌으로써, 테스트 환경에서만 사용되게 하였다.

2) 테스트 코드

테스트 코드는 다음과 같이 작성할 수 있다.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataJpaTest
public class AccountRepositoryTest {

  @Autowired
  AccountRepository accountRepository;

  @Test
  public void di() throws SQLException {
    Account account = new Account();
    account.setUsername("heusmi");
    account.setPassword("pass");

    Account newAcoount = accountRepository.save(account);
    assertThat(newAcoount).isNotNull();
}

@SpringBootTest 가 아닌 @DataJpaTest 를 활용해서, 모든 Bean 을 다 띄우지 않고 JPA 테스트에 필요한 Bean 만 띄울 수 있다.

만약 SpringBootTest 로 띄우고 싶다면 다음과 같이 properties 속성을 주면 된다.

@RunWith(SpringRunner.class)
@SpringBootTest(properties = "spring.datasource.url={테스팅용 db url}")
public class AccountRepositoryTest {
  ...
}

위 예제는 accounth2 DB 에 넣고, 잘 넣었으면 Null 값이 아니므로, 성공적인 테스팅을 수행할 것이다.

Query Method

JPA Repostiory 클래스 안에서 일부 메쏘드를 통해 쿼리문을 보낼 수 있다.

1) findBy 로 데이터 조회하기

AccountRepository 클래스를 다음과 같이 수정하자.

public interface AccountRepository extends JpaRepository<Account, Long> {
  Account findByUsername(String username);
}

Account findByUsername(String username) 메쏘드가 추가 되었는데, 이는 테이블에서 username 에 해당하는 데이터만 조회하여 반환한다는 뜻이다.

그 외 별도의 쿼리문을 작성하거나 코드를 더하지 않아도 작동한다.
즉, findBy필드(필드타입 이름) 으로 메쏘드를 작성하면, JPA 가 알아서 조회할 수 있도록 약속된 것이다.

다음과 같이 테스팅 해볼 수 있다.

@RunWith(SpringRunner.class)
@DataJpaTest
public class AccountRepositoryTest {

  @Autowired
  AccountRepository accountRepository;

  @Test
  public void di() throws SQLException {
    Account account = new Account();
    account.setUsername("heusmi");
    account.setPassword("pass");

    Account newAcoount = accountRepository.save(account);
    assertThat(newAcoount).isNotNull();

    Account existingAccount = accountRepository.findByUsername(newAcoount.getUsername());
    assertThat(existingAccount).isNotNull();
  }
}

2) @Query 로 커스텀 메쏘드 만들기

@Query(nativeQuery = true, value = "SQL") 를 이용해서, JPA Repostiory 클래스 내 메쏘드를 정의할 수 있다.

예를 들면, 이전의 findByUsername 를 다음과 같이 정의할 수 있다.

public interface AccountRepository extends JpaRepository<Account, Long> {
  @Query(nativeQuery = true, value = "SELECT * FROM account WHERE username = '{0}'")
  Account findByUsername(String username);
}