-
Spring Boot JPA 사용법프로그래밍/서버 프로그래밍 2018. 12. 20. 13:42
오늘은 지난번에 알아보았던 JPA를 스프링에서 어떻게 적용하는 지 함께 알아보겠습니다.
저는 Spring Boot를 이용해서 실습을 진행해보겠습니다.
본 실습은 jojoldu님의 블로그를 보면서 진행했습니다. (https://jojoldu.tistory.com/251?category=635883)
1.Dependency 추가
먼저 저는 maven을 사용하므로 pom.xml에 관련 dependency를 넣어주겠습니다!
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
data jpa는 JPA관련이고, spring-boot-starter-test는 테스트 관련인데 H2는 무엇인지 들어보셨나요?
H2
는 MySQL, oracle, 등과 같은 평범한 DB이지만, 초경량이라는 점과 In Memory DB 를 지원하는 점이 특징입니다.그래서 타 DB에 비해 속도가 빠르지만 지속성이 없기때문에?( 컴퓨터 종료 혹은 메모리 종료시 내용이 날라감.) 테스트용으로 매우 좋고, 캐싱용으로도 많이 사용된다고 합니다. 더 자세한 설명은 Google 혹은위키로.....
다음은 lombok이라는 라이브러리도 들어보신 분도 많겠지만, 아직 모르는 분도 계실 거라고 생각합니다. lombok 은 자바에서 클래스를 생성할 때 보통 반복적으로 적게되는 ToString, Getter, Setter, 등을 Annotation 하나로 간단히 처리해줍니다.
@Getter @Setter public class User { private String userName; private String userAge; }
이런 식으로 작동한답니다.
lombok은 다른 라이브러리와 다르게 dependency만 추가해준다고 바로 적용되지않고, IDE에 적용을 추가적으로 해줘야하는데, 이 설치법과 lombok을 사용할 때 주의사항은 Hyoj 님의 블로그에 설명이 매우 잘되어있어서 링크로 대체하겠습니다.
2. Entity 클래스 생성
이제 드디어 JPA를 테스트해보기위한 Entity클래스를 하나 만들어보겠습니다!
@NoArgsConstructor(access = AccessLevel.PROTECTED) @ToString @Getter @Entity public class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(length = 20, nullable = false) private String name; @Column(length = 20, nullable = false, unique = true) private String phone; @Builder public Customer(String name, String phone) { this.name = name; this.phone = phone; } }
Annotation이 너무 많아서 처음엔 조금 헷갈리실 수도 있습니다. 혹시 lombok을 사용하지 않으시는 분들은 코드내의
@ToString, @Getter, @Builder
를 빼고 직접 생성해주시고 나서 진행해주세요!Customer 에는 총 3개의 필드가 존재합니다.
id
필드는@id
를 사용하여 기본키(PK
)로 지정합니다. 이때 키를 직접할당하는 방식이 아닌, 자동으로 생성되도록 하기위해@GeneratedValue
를 사용합니다.GenerationType.IDENTITY는 기본 키 생성을 데이터베이스에 위임하는 방식이고, 다른 방식들은
- IDENTITY
- SEQUENCE
- TABLE
- AUTO
정도가 있습니다.
name, phone
필드의@Column
Annotation은 데이터베이스 컬럼으로 지정해줍니다. 안에length
와nullable
또는unique
와 같은 설정들이 가능합니다. 이외에도 다영한 설정이 들어갈 수 있습니다.또한,
@Column
을 생략할 경우 필드명을 사용하여 컬럼명과 매핑하기 때문에 만약 DB가 대소문자를 구분하는 경우에는 반드시@Column
Annotation을 사용하는 것이 좋습니다.
3. Repository 클래스 생성
JPA에서는 단순히 Repository 인터페이스를 생성한후 JpaRepository<Entity, 기본키 타입> 을 extends하면 기본적인 Create, Read, Update, Delete가 자동으로 생성됩니다! 그래서 저흰 그냥 인터페이스를 만들고, 상속만 잘해주면 기본적인 동작을 테스트해볼 수 있는거죠 :D
@Repositoryd public interface CustomerRepository extends JpaRepository<Customer, Long>{ //비워있어도 잘 작동함. // long 이 아니라 Long으로 작성. ex) int => Integer 같이 primitive형식 사용못함 }
4. Test 코드 작성 및 테스트
이제 JUnit 을 이용하여 테스트를 작성해봅니다. 테스트 코드는
import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @RunWith(SpringRunner.class) @SpringBootTest public class CustomerRepositoryTests { @Autowired CustomerRepository customerRepository; @Test public void testCustomerRepository(){ Customer customer = Customer.builder().name("크리스").phone("010-1224-1225").build(); customerRepository.save(customer); List<Customer> customerList = customerRepository.findAll(); Customer chris = customerList.get(0); assertThat(chris.getName(), is("크리스")); assertThat(chris.getPhone(), is("010-1224-1225")); } @After public void deleteAll() { customerRepository.deleteAll(); } }
이런 식으로 작성되어 있습니다.
테스트 클래스를 우클릭 후 Run As 에서 JUnit Test를 눌러서 테스트를 진행하였더니,
테스트에 성공하였습니다! :-)
4. Repository 수정
이번에는
CustomerRepository
에 수정을 가해서 테스트 코드의findAll()
부분을findByName 혹은
findByPhone`으로 바꿔보기위해CustomerRepository
부분을 수정해보겠습니다.쿼리를 유추할 수 있는 메소드의 이름으로 쿼리를 정의하여주면 자동으로 이에 맞는 쿼리를 실행하여 줍니다.
먼저
CustomerRepository
를 수정합니다.@Repository public interface CustomerRepository extends JpaRepository<Customer, Long>{ public List<Customer> findByName(String name); public List<Customer> findByPhone(String phone); //like검색도 가능 public List<Customer> findByNameLike(String keyword); }
findBy뒤에 컬럼명을 붙여주면 이를 이용한 검색이 됩니다. 따로 내부 구현을 하지 않아도 알아서 마법처럼 작동합니다!
이외에도 메소드 생성시 다양한 키워드들을 지원하는 데 대표적으로는
- And
- Or
- Is, Equals
- LessThan, LessThanEqual
- GreaterThan, GreaterThanEqual
- 기타 등등( 아라한사님이 번역해주신 스프링 데이터 JPA 레퍼런스 를 보시면 더 많은 키워드와 정보를 얻을 수 있습니다. )
5.컨트롤러를 이용한 테스트
이번에는 JUnit 이 아니라 PostMan을 이용해서 작성한 메소드들이 작동하는 지 확인해보겠습니다.
먼저
Controller
를 작성해야겠죠?@RestController @EnableAutoConfiguration @RequestMapping(value = "/customer") public class CustomerController { @Autowired CustomerRepository customerRepository; @PostMapping("/") public @ResponseBody List<Customer> createCustomer(@RequestBody Map<String,String> param){ String name = param.get("name"); String phone = param.get("phone"); Customer customer = Customer.builder().name(name).phone(phone).build(); customerRepository.save(customer); return customerRepository.findAll(); } }
이렇게 확인을 위해 간단히 만들어줬습니다. 이제 PostMan으로 요청을 보내보겠습니다.
이렇게 응답이 오는 것을 확인할 수 있습니다. 이 상태에서
phone
은 유니크이므로 변경한 후 한번 더 요청을 보내면id
가2
인 데이터가 하나 더 생겨있겠죠?저희가 원하는 결과가 나온 걸 확인할 수 있습니다!
다른 메소드들도 테스트해보면 잘 작동합니다.
직접 사용해보니 JPA가 MyBatis 에 비하여 왜 더 생산속도가 빠른지 느낄 수 있었습니다.
긴 글 읽어주셔서 감사합니다! :D
모두 좋은하루 되세요
sample code는 https://github.com/junwoochoi/spring-jpa-practice-sample 에 올라와 있습니다.
아직 모르는게 많아 게시글에 잘못된 정보가 있을 수 있습니다. 혹시 잘못된 정보가 있다면, 댓글 혹은 메일로 알려주시면 최대한 빨리 수정하겠습니다!
'프로그래밍 > 서버 프로그래밍' 카테고리의 다른 글
@Valid 에서 받은 Errors를 Serialize해서 ResponseEntity에 담자! (0) 2019.02.19 스프링 시큐리티 요청 URI별 권한 처리할 때 문제상황 해결! (0) 2019.02.19 Spring boot 스프링 부트에서 request Validation 요청값 검증하기 (0) 2019.02.18 DTO란 (0) 2019.02.15 Spring 스프링 MyBatis 와 JPA-Hibernate (0) 2018.12.18