아래 강의 정리
목차
- 회원 리포지토리 개발
- 회원 서비스 개발
- 회원 기능 테스트
회원 기능
- 회원 등록 : save
- 회원 목록 조회 : findOne, findAll, findByName
회원 리포지토리 개발
- @Repository : 스프링 빈으로 등록, JPA 예외를 스프링 기반 예외로 예외 변환한다.
- @PersistenceContext : 스프링이 엔티티 매니저(EntityManager)를 만들어 injection 해준다.
- JPQL은 SQL과 거의 같지만, SQL은 테이블 대상 쿼리라면, JPQL 엔티티 대상 쿼리다.
- @PersistenceUnit : 엔티티 메니터 팩토리 주입한다.
회원 서비스 개발
- @Service : 들어가면 @Component 있다.
- em.persist()하면 영속성 컨텍스트에 멤버 객체를 올린다. 이 때 영속성 컨텍스트는 key, value가 있는데 key값이 id가 된다. DB PK와 매핑한게 key가 된다. @GeneratedValue하면 DB마다 다른데, 알아서 id값이 생성됨이 보장된다.
영속성 컨텍스트에 값을 넣어야 하는데, key는 PK 값이다. 그러며 동시에 id에 값을 채워준다. DB에 들어간 시점이 아니어도 그렇게 해준다. - @Transactional : 트랜잭션, 영속성 컨텍스트
- JPA의 데이터 변경이나 로직은 모두 트랜잭션 안에서 실행되어야 한다.
- readOnly=true : 데이터 변경이 없는 읽기 전용 메서드에서 사용한다. 영속성 컨텍스트를 플러시 하지 않으므로 약간의 성능 향상(읽기 전용에는 다 적용)
- 데이터베이스 드라이버가 지원하면, DB에서 성능 향상된다.
- 현재 프로젝트에선, class 위에 @Transactional(readOnly = true)를 해두고, 읽기가 아닌 메서드에는 따 @Transactional을 적용해두었다.
기본은 @Transactional(readOnly=false)이기 때문에, 따로 설정한 것은 이것이 우선권을 가진다. 뭐 이건 개인 선택이다.
- validateDuplicateMember를 설정해도 문제가 발생할 수 있다.
둘 이상이 동시에 통과하면, 동시에 save를 호출하게 될 수 있고, 그러면 둘이 같은 이름으로 저장될 수 있다. 현재 프로젝트에선 이게 문제가 된다.
따라서 한 번더 최후의 방어를 해야한다. 멀티 쓰레드 상황을 고려해 제약조건 이런거 잘 고려해봐야한다.
// 1. 필드 주입
@Autowired
private MemberRepository memberRepository;
// 2. 생성자 주입
private final MemberRepository memberRepository;
@Autowired // 생성자 하나면, 생략 가능
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
- 보통 필드 주입으로 많이 쓰지만 단점이 많다.
- 변경 불가능한 안전한 객체 생성이 가능하다.
- access할 수 없으니 값을 바꾸지 못해, 테스트 할 때랑 불편하다.
- 그래서 생성자 주입 setter Injection을 많이 사용한다.
- 가장 권장하는 방법이다.
- 테스트코드 작성할 때 값을 직접 주입할 수 있다.
- final 키워드를 추가하면, 컴파일 시점에 memberRepository를 설정하지 않는 오류를 체크할 수 있다.
Lombok
- @AllArgsConstructor : 필드의 생성자를 만들어준다.
- @RequiredArgsConstructor : final이 있는 필드만 가지고 생성자를 만들어준다.
- : 스프링 데이터 JPA를 사용하면 EntityManager 도 주입 가능하다. 그래서 @Require~로 바
회원 기능 테스트
테스트 요구사항
- 회원가입을 성공해야 한다.
- 회원가입 할 때 같은 이름이 있으면, 예외가 발생한다.
기술 설명
- @RunWith(SpringRunner.class) : 스프링과 테스트 통합
- @SpringBootTest : 스프링 부트 띄우고 테스트 (이게 없으면 @Autowired 다 실패한다.)
- @Transactional : 반복 가능한 테스트 지원, 각각의 테스트를 실행할 때마다, 트랜잭션을 시작하고, 테스트가 끝나면 트랜잭션을 강제로 롤백한다. (이 어노테이션이 테스트 케이스에서 사용될 때만 롤백)
- 회원가입 테스트를 실행해보면, insert문이 생기지 않았다.
메서드 타고 들어가서 save()를 보면, persist()를 한다. DB마다 전략이 다르지만, 기본적으로 persist()를 해도 Insert문이 발생하지 않는다. 특히 generate value 전략에서.
-> DB 트랜잭션이 commit될 때, flush()가 되면서 insert문이 나간다. 따라서 commit이 엄청 중요하다.
여기선 @Transactional로 인해 롤백이 되는데, 확인을 하고싶다면, @Rollback(false)하거나, 엔티티 매니저 만들어flush()하면 된다. - fail() : Assert에서 제공해주는 메서드. 코드가 여기까지 오면, 무언가 잘못된 것이라 판단하고 fail을 띄운다.
- 아래 옵션을 추가하면, 코드를 깔끔하게 작성할 수 있다.
@Test(expected = IllegalStateException.class)
테스트 케이스를 위한 설정
- 테스트는 케이스 격리된 환경에서 실행하고, 끝나면 데이터를 초기화하는 것이 좋다.
- 그런 면에서 메모리 DB를 사용하는 것이 가장 이상적이다.
- 테스트 케이스를 위한 스프링 환경과, 일반적으로 애플리케이션을 실행하는 환경은 보통 다르므로, 설정 파일을 다르게 사용하자.
- test 폴더에 resources 디렉토리를 추가하면, 테스트에선 이 폴더의 application.yml이 우선권을 가진다.
이 파일의 url 값을 변경해준다.
h2database.com -> Cheat Sheet -> Embedded -> In-Memor
이러면 H2 종료해도 테스트 잘 된다. - 그런데, datasource 설정이 없으면, 기본적으로 메모리 DB를 사용하고, driver-class도 현재 등록된 라이브러리를 보고 찾아준다.
- 추가로 ddl-auto도 createdrop 모드로 동작한다. 따라서 데이터 소스나, JPA 관련된 별도의 추가 설정을 하지 않아도 된다.
'프로그래밍 > Spring' 카테고리의 다른 글
[Spring boot / JPA] 6. 주문 도메인 개발 (0) | 2023.07.03 |
---|---|
[Spring boot / JPA] 5. 상품 도메인 개발 (0) | 2023.07.02 |
[Spring boot / JPA] 3. 애플리케이션 구현 준비 (0) | 2023.06.30 |
[Spring boot / JPA] 2. 도메인 분석 설계 (0) | 2023.06.29 |
[Spring boot / JPA] 1. 프로젝트 환경설정 (0) | 2023.06.28 |