티스토리 뷰
계층형 구조 사용
- controller , web : 웹 계층
- service : 비즈니스 로직 , 트랜잭션 처리
- repository : JPA를 직접 사용하는 계층 , 엔티티 매니저 사용
- domain : 엔티티가 모여있는 계층 , 모든 계층에서 사용
패키지 구조
- jpabook.jpashop
- domain
- exception
- repository
- service
- web
1. 서비스 , 리포지토리 계층 개발
2. 테스트 케이스 작성 , 검증
3. 웹 계층 적용
회원 리포지토리
@Repository
@RequiredArgsConstructor
public class MemberRepository {
private final EntityManager em;
public void save(Member member){
em.persist(member);
}
public Member findOne(Long id){
return em.find(Member.class , id);
}
public List<Member> findAll(){
return em.createQuery("select m from Member m" , Member.class)
.getResultList();
}
public List<Member> findByName(String name){
return em.createQuery("select m from Member m where m.name = :name" , Member.class)
.setParameter("name",name)
.getResultList();
}
}
- @Repository : 스프링 빈으로 등록 , JPA 예외를 스프링 기반 예외로 예외 변환
- @PersistenceContext : EntityManager 주입
- @PersistenceUnit : EntityManagerFactory 주입
회원 서비스
@Service
@Transactional(readOnly = true)
//@Transactional을 메소드 레벨에 적용하여 readOnly를 구분하여주면 성능면에 이점이 많다.
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
// 회원 가입
@Transactional(readOnly = false)
public long join(Member member){
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
// EXCEPTION 회원 중복 체크
List<Member> members = memberRepository.findByName(member.getName());
if(!members.isEmpty()){
throw new IllegalStateException("이미 존재하는 회원입니다.");
}
}
// 회원 전체 조회
public List<Member> findMembers(){
return memberRepository.findAll();
}
// 회원 단건 조회
public Member findOne(Long memberId){
return memberRepository.findOne(memberId);
}
}
- @Transactional : 영속성 컨텍스트
- readOnly=true 데이터의 변경이 없는 읽기 전용 메서드에 사용 (읽기 전용에는 다 적용)
- 데이터베이스 드라이버가 지원하며 DB에서 성능 향상
- 생성자 주입 방식을 권장
- 변경 불가능한 안전한 객체 생성 가능
- 생성자가 하나면 @Autowired를 생략할 수 있다.
- final 키워드를 추가하면 컴파일 시점에 memberRepository를 설정하지 않는 오류를 체크할 수 있다.
회원 기능 테스트
@SpringBootTest
@Transactional
class MemberServiceTest {
@Autowired
MemberService memberService;
@Autowired
EntityManager em;
@Test
//@Rollback(false)
// 테스트에서 Transactional은 Rollback 되기 때문에 Rollback을 false로 하여 commit되게 한다.
public void 회원가입 () throws Exception {
// given
Member member = new Member();
member.setName("jeong");
// when
Long saveId = memberService.join(member);
// then
//em.flush(); // Transactionl 떄문에 Rollback 되어야 하지만 강제로 반영
Assert.assertEquals(member , memberService.findOne(saveId));
}
@Test
public void 중복_회원_예외() throws Exception {
// given
Member member = new Member();
member.setName("jeong1");
Member member2 = new Member();
member2.setName("jeong1");
// when
memberService.join(member);
// then
IllegalStateException exception =
Assertions.assertThrows(IllegalStateException.class ,() -> memberService.join(member2));
Assertions.assertEquals("이미 존재하는 회원입니다." , exception.getMessage());
}
}
- @SpringBootTest : 스프링 부트 띄우고 테스트 , 이게 없으면 @Autowired 다 실패
- @Transactional : 반복 가능한 테스트 지원 , 각각의 테스트를 실행할 때 마다 트랜잭션을 시잔하고 테스트가 끝나면 트랜잭션을 강제로 롤백 , (이 어노테이션이 테스트 케이스에서 사용될 때만 롤백)
테스트 케이스를 위한 설정
- 테스트는 격리된 환경에서 실행하고 , 끝나면 데이터를 초기화하는 것이 좋다. 그런 면에서 메모리 DB를 사용하는 것이 가장 이상적이다.
- 추가로 테스트 케이스를 위한 스프링 환경과 , 일반적으로 애플리에키션을 실행하는 환경은 보통 다르므로 설정 파일을 다르게 사용하자
- 다음과 같이 간단하게 테스트용 설정 파일을 추가하면 된다.
- test/resources/application.yml
spring:
# datasource:
# url: jdbc:h2:mem:test
# username: sa
# password:
# driver-class-name: org.h2.Driver
#
# jpa:
# hibernate:
# ddl-auto: create
# properties:
# hibernate:
# format_sql: true
logging.level:
org.hibernate.SQL: debug
org.hibernate.type: trace
// #은 yml의 주석이다
- 이제 테스트에서 스프링을 실행하면 이 위치에 있는 설정 파일을 읽는다.
- (만약 이 위치에 없으면 src/resources/application.yml을 읽는다)
- 스프링 부트는 datasource 설정이 없으면 기본적으로 메모리 DB를 사용하고 ,
- driver-class도 현재 등록된 라이브러를 보고 찾아준다.
- ddl-auto도 create-drop모드로 동작한다.
- 따라서 데이터소스나 JPA관련된 별도의 추가 설정을 하지 않아도 된다.
'기록 > 스프링 부트 와 JPA 활용' 카테고리의 다른 글
웹 계층 개발 (0) | 2021.01.31 |
---|---|
주문 도메인 개발 (0) | 2021.01.30 |
상품 도메인 개발 (0) | 2021.01.30 |
도메인 분석 설계 (0) | 2021.01.27 |
스프링 부트와 JPA 프로젝트 환경설정 (0) | 2021.01.24 |
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 변경감지
- 메서드 레퍼런스
- 스태틱 메서드
- 스프링부트
- function패키지
- 싱글 톤
- 빈 생명주기
- 프로토타입 빈
- 의존관계 주입
- 생성자 주입
- H2 DB
- Iterable
- JPA
- 람다 표현식
- 클라이언트 서버 구조
- 싱글톤 빈
- completablefuture
- 티스토리 Open API
- 함수형 인터페이스
- HTTP 메시지
- Functional Interface
- stream
- 싱글 톤 빈
- @configuration
- 기본 제공 함수형 인터페이스
- java8
- 준영속 엔티티
- 스프링 빈 등록
- annotation container
- 기본 메서드
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함