Spring Boot - ORM, Spring Data JPA
업데이트:
스프링 부트 활용
Spring Data 5부 : ORM, JPA, Spring Data JPA 개요
ORM, JPA, Spring Data JPA에 대해 알아보자.
ORM (Object Relational Mapping)
-
객체와 관계형 DB 테이블을 맵핑 할 때 발생하는 개념적 불일치를 해결하는 프레임워크이다.
-
ORM은 아래의 예시들과 같은 문제를 관리하고 해결해준다,1. 클래스는 타입이 다양하지만, 테이블에는 컬럼과 밸류값이 전부이다. 이를 어떻게 일치시킬 것인가 2. 클래스 간의 상속구조를 어떻게 테이블에서 맵핑할 것인가 3. identity 문제를 어떻게 관리할 것인가. 관계형 DB에서 id는 id, primary key, foreign key 등으로 관리 할 수 있다. 클래스 객체에서 id는 무엇을 기준으로 해야 하는가? hash code? equals method? 4. 객체의 identity가 같다면 어느 엔티티가 같아야 같은 객체로 볼 수 있는가? id가 null인 경우에는 어떻게 처리할까? -
위와 같이 발생할 수 있는 개념적 불일치를 ORM이 솔루션을 제시하여 해결해준다.
-
JPA는 이런ORM솔루션 중에서Java표준을 정한 것이다. -
대부분의
Java표준이Hibernate기반이고, 대부분의JPA의 기능도Hibernate을 기반하여 만들어졌다. -
하지만
JPA가Hibernate의 모든 기능을 커버하진 못하지만, 약간의 설정으로 해결가능하여 사용에 지장은 없다. -
그렇다면
JPA와Spring Data JPA의 차이는 무엇일까?Spring Data JPA는 이러한JPA기능을 아주 쉽게 사용할 수 있도록 스프링 데이터로 추상화 해놓은 것이다. -
추상화 :
Spring Data JPA>JPA>Hibernate>Datasource (JDBC)- 결국 여기서 추상화란
Spring Data JDBC의 모든 기능을 사용하면서, 부가적으로Spring Data JPA를 위한 기능들을 추가한 것이다.
- 결국 여기서 추상화란
-
의존성을 살펴보면
spring-boot-starter-data-jpa하위에hibernate-core가JPA의 구현체이다.
Spring Data 6부 : Spring Data JPA 연동
Spring Data JPA
-
Repository빈 자동 생성 -
쿼리 메서드 자동 구현
-
원래 사용을 위해서는
@EnableJpaRepositories를 붙여 설정을 해야하지만, 스프링 부트가 자동으로 설정해준다. -
아래 의존성을 추가하면 스프링 부트가 모든 자동설정을 지원해준다.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>2.2.6.RELEASE</version> </dependency> -
인메모리 데이터베이스가 아닌 데이터베이스를 사용하려면
application.properties에서 연결 설정을 해줘야 한다. 설정하지 않으면 인메모리로 띄운다.spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=henry spring.datasource.password=1234
@DataJpaTest (슬라이스 테스트)
-
Repository와 관련된 빈들만 등록을 하여 테스트한다. -
슬라이스 테스트 환경에는 인메모리 데이터베이스(
H2)가 필요하다.// test 환경에서만 동작한다. <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>test</scope> </dependency> -
애플리케이션과 테스트가 다른
DB를 사용할 수 있다. (애플리케이션 :MySQL, 테스트 :H2)@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 = dataSource.getConnection().getMetaData(); System.out.println(metaData.getURL()); System.out.println(metaData.getDriverName()); System.out.println(metaData.getUserName()); } } @Test public void account() { Account account = new Account(); account.setUsername("henry"); account.setPassword("pass"); Account newAccount = accountRepository.save(account); assertThat(newAccount).isNotNull(); Optional<Account> existingAccount = accountRepository.findByUsername(newAccount.getUsername()); assertThat(existingAccount).isNotEmpty(); Optional<Account> nonExistingAccount = accountRepository.findByUsername("wooody92"); assertThat(nonExistingAccount).isEmpty(); } }// result jdbc:h2:mem:1f515463-6796-405b-9ef6-e81f8fad4096 H2 JDBC Driver SA -
@DataJpaTest대신@SpringBootTest(통합 테스트)를 사용한다면 DB를 구분하는 것이 안전하다.- 그렇지 않으면 테스트 환경에서의 DB변경이 애플리케이션 DB에 영향을 준다.
-
통합 테스트를 사용하여 DB 설정을 나눈다면,
@SpringBootTest(properties = "spring.datasource.url=")을 사용하여 오버라이드 할 수 있다. -
하지만 슬라이스 테스트가 빠르고 간단하고 안전하므로 권장한다.
-
Repository에서 아래와 같이 다양한 방식으로 메서드를 생성할 수 있다.// 자동생성 (규칙에 맞추어 이름을 지어야 한다.) Optional<Account> findByUsername(String userName); // jpql @Query("jpql 명령어") Optional<Account> findByUsername(String userName); // native query @Query(nativeQuery = true, value = "SELECT * FROM account WHERE username = :userName") Optional<Account> findByUsername(String userName);
댓글남기기