개발강의정리/Spring

[스프링 부트 개념과 활용] 4-10. 스프링 데이터 6부: Spring-Data-JPA 연동

nineDeveloper 2019. 11. 21.
728x90

스프링 부트 개념과 활용

4. 스프링 부트 활용

포스팅 참조 정보

GitHub

공부한 내용은 GitHub에 공부용 Organizations에 정리 하고 있습니다

해당 포스팅에 대한 내용의 GitHub 주소

실습 내용이나 자세한 소스코드는 GitHub에 있습니다
포스팅 내용은 간략하게 추린 핵심 내용만 포스팅되어 있습니다

https://github.com/freespringlecture/springboot-concept-uses/tree/chap04-10-06-data-jpa_interwork

 

freespringlecture/springboot-concept-uses

백기선님의 스프링 부트 개념과 활용 강의 내용 정리. Contribute to freespringlecture/springboot-concept-uses development by creating an account on GitHub.

github.com

해당 포스팅 참고 인프런 강의

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard

 

스프링 부트 개념과 활용 - 인프런

스프링 부트의 원리 및 여러 기능을 코딩을 통해 쉽게 이해하고 보다 적극적으로 사용할 수 있는 방법을 학습합니다. 중급 프레임워크 및 라이브러리 Spring Spring Boot 온라인 강의

www.inflearn.com

실습 환경

  • Java Version: Java 11
  • SpringBoot Version: 2.1.2.RELEASE

10. 스프링 데이터 6부: Spring-Data-JPA 연동

h2를 test 의존성으로 추가

TEST는 h2를 사용

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

PostgreSQL 의존성 추가

Application을 실행할때는 PostgreSQL을 사용

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
</dependency>

스프링 데이터 JPA 사용하기

  • @Entity 클래스 만들기
  • Repository 만들기

스프링 데이터 리파지토리 테스트 만들기

슬라이스 테스트란 Reopository와 Repository와 관련된 빈 들만 등록을 해서 테스트를 만드는 것

  • H2 DB를 테스트 의존성에 추가하기

@DataJpaTest (슬라이스 테스트) 작성

@DataJpaTest를 사용하지 않고 @SpringBootTest로 테스트 하면 integration 테스트 임
Application에 있는 @SpringBootApplication을 찾아서 모든 빈들을 다 등록하고 application.properties가 적용되고 postgreSQL 사용하게됨
@SpringBootTest(properties = "spring.datasource.url=''") 로 다른 데이터베이스를 설정해서 사용이 가능하긴 하지만
테스트 할때는 In-memory 데이터베이스로 테스트 하기를 권장함
슬라이스 테스트를 할 때는 반드시 In-memory 데이터베이스가 필요 하므로 H2를 test 의존성으로 추가

이전시간에 했던 PostgreSQL Docker 시작

docker start postgres_boot
docker ps

PostgreSQL Wanning 해결법

드라이버가 createClob()라는 Method를 지원하지않아서 Wanning이 발생

항목 내용
경고 org.postgresql.jdbc.PgConnection.createClob() is not yet implemented
해결 spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

DatabaseMetaData 확인 테스트 코드

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

    @Autowired
    DataSource dataSource;

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    AccountRepository accountRepository;

    @Test
    public void di() throws SQLException {

        try(Connection connection = dataSource.getConnection()){
            DatabaseMetaData metaData = connection.getMetaData();
            System.out.println(metaData.getURL());
            System.out.println(metaData.getDriverName());
            System.out.println(metaData.getUserName());
        }
    }
}

Entity Account 클래스 작성

equals & hashcode도 추가

@Entity
public class Account {

    @Id
    @GeneratedValue //Repository를 통해 저장을 할 때 ID를 자동으로 생성
    private Long id;
    private String username;
    private String password;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Account account = (Account) o;
        return Objects.equals(id, account.id) &&
                Objects.equals(username, account.username) &&
                Objects.equals(password, account.password);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, username, password);
    }
}

JpaRepository 인터페이스 작성

//JpaRepository< Entity의 타입, ID의 타입>
public interface AccountRepository extends JpaRepository<Account, Long> {
    Account findByUsername(String username);
}

테스트 코드 작성

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

    @Autowired
    DataSource dataSource;

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    AccountRepository accountRepository;

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

        // 새로운 account 등록
        Account newAccount = accountRepository.save(account);
        // 새로운 account가 등록 됐는지 확인
        assertThat(newAccount).isNotNull();

        // 새로운 account의 username으로 조회해서 데이터가 있는지 확인
        Account existingAccount = accountRepository.findByUsername(newAccount.getUsername());
        assertThat(existingAccount).isNotNull();

        // 없는 username으로 조회해서 데이터가 없는지 확인
        Account nonExistingAccount = accountRepository.findByUsername("ironman");
        assertThat(nonExistingAccount).isNull();
    }
}

JpaRepository Optional로 변경

//JpaRepository< Entity의 타입, ID의 타입>
public interface AccountRepository extends JpaRepository<Account, Long> {
    Optional<Account> findByUsername(String username);
}

Optional로 테스트 코드 변경

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

    @Autowired
    DataSource dataSource;

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    AccountRepository accountRepository;

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

        // 새로운 account 등록
        Account newAccount = accountRepository.save(account);
        // 새로운 account가 등록 됐는지 확인
        assertThat(newAccount).isNotNull();

        // 새로운 account의 username으로 조회해서 데이터가 있는지 확인
        Optional<Account> existingAccount = accountRepository.findByUsername(newAccount.getUsername());
        assertThat(existingAccount).isNotEmpty();

        // 없는 username으로 조회해서 데이터가 없는지 확인
        Optional<Account> nonExistingAccount = accountRepository.findByUsername("ironman");
        assertThat(nonExistingAccount).isEmpty();
    }

native Query사용법

아래와 같은 형식으로 nativeQuery로 사용해도 되지만 JPA에서 제공하는 Query Languge를 사용해서 JPQL로 작성하는 것을 권장

//JpaRepository< Entity의 타입, ID의 타입>
public interface AccountRepository extends JpaRepository<Account, Long> {
    @Query(nativeQuery = true, value = "select * from account where username = '{0}]")
    Account findByUsername(String username);
}
728x90

댓글

💲 추천 글